For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > April 2004 > Hash ref's of hash's









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Hash ref's of hash's
mgoland@optonline.net

2004-04-01, 6:33 pm


Hi all,
I am trying to setup a hash who's values are referance to hash's. Data structure should look like this

hash
1:
setting 1
setting 2
2:
setting 1
setting 2
.....

I would think it can be accomplished with following code, but when I try to print it out it only prints the last setting which it read. Any idea's ??

CODE:
#!perl -w
use strict;
open RD, "input.txt";

my ( $field,$portsetting, $value, $port, $portnum, %digi, $debug );
$debug=0;

while ( <RD> ) {
if(m/^(port)\s\=\s(.*)$/i){$portnum=$2;$portnum++}

$field = {};
$digi{$portnum} = $field;

m/^(.*)\s\=\s(.*)$/;
$portsetting=$1;
$value=$2;
$field->{$portsetting}=$value;

print "setting $portsetting -> $digi{$portnum}{$portsetting}\n" if $debug;

if($portsetting eq 'porttitle'){
$value =~ tr /-/ /;
$value =~ m/^(\w+)\s+(\w+)/i;
$field->{$portsetting}=$1;
$field->{'type'}=$2;
print "1:$digi{$portnum}{$portsetting}\t2:$digi{$portnum}{'type'}\n" if $debug;
}

}


# print the whole thing
foreach $port ( keys %digi ) {
print "$port: { ";
for $field ( keys %{ $digi{$port} } ) {
print "$field=$digi{$port}{$field} ";
}
print "}\n";
}

Sample DATA

port = 0
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol = 1
port = 1
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol = 1

Wiggins D'Anconia

2004-04-01, 9:31 pm

mgoland@optonline.net wrote:
> Hi all,
> I am trying to setup a hash who's values are referance to hash's. Data structure should look like this
>
> hash
> 1:
> setting 1
> setting 2
> 2:
> setting 1
> setting 2
> ....


This does not look like a HoH, but a HoA.

>
> I would think it can be accomplished with following code, but when I try to print it out it only prints the last setting which it read. Any idea's ??
>
> CODE:
> #!perl -w
> use strict;
> open RD, "input.txt";


Always check that open succeeded.

open RD, "input.txt" or die "Can't open file: $!";

>
> my ( $field,$portsetting, $value, $port, $portnum, %digi, $debug );
> $debug=0;
>


Declaring all of your variables up front reduces the help that 'strict'
can provide and generally leads to more problems. It may be that $field
is getting reused because even though you are "emptying" it, this isn't
clear to me.

> while ( <RD> ) {


Let's dispense with $_ it adds confusion when we should be trying to be
explicit. Once you don't have to ask questions about references then
consider going back to it.

while (my $line = <RD> ) {

> if(m/^(port)\s\=\s(.*)$/i){$portnum=$2;$portnum++}
>


Whitespace is our friend, why are we capturing a constant?

if ($line =~ m/^port\s=\s(.*)$/i) {
$portnum = $1;
}

> $field = {};
> $digi{$portnum} = $field;
>


Double assignment?

> m/^(.*)\s\=\s(.*)$/;


If we are going to capture we should double check that the string is
formatted properly, put this into an if.

if ($line =~ m/^(.*)\s=\s(.*)$/) {

There's no real need for the temp variables but if you want them that is
fine for readability.

> $portsetting=$1;
> $value=$2;
> $field->{$portsetting}=$value;
>


> print "setting $portsetting -> $digi{$portnum}{$portsetting}\n" if $debug;
>
> if($portsetting eq 'porttitle'){
> $value =~ tr /-/ /;
> $value =~ m/^(\w+)\s+(\w+)/i;


Again if you are going to run a match make sure it succeeds, especially
when capturing. As a side note your sample data did not contain this.

> $field->{$portsetting}=$1;
> $field->{'type'}=$2;
> print "1:$digi{$portnum}{$portsetting}\t2:$digi{$portnum}{'type'}\n" if $debug;
> }
>
> }
>
>
> # print the whole thing
> foreach $port ( keys %digi ) {
> print "$port: { ";
> for $field ( keys %{ $digi{$port} } ) {
> print "$field=$digi{$port}{$field} ";
> }
> print "}\n";
> }
>


If this is just for debugging take a look at Data::Dumper it is much easier.

> Sample DATA
>
> port = 0
> bmanset = 0
> benable = 1
> uarttype = 0
> baudrate = 9600
> stopbits = 1
> databits = 8
> parity = 0
> flowcontrol = 0
> protocol = 1
> port = 1
> bmanset = 0
> benable = 1
> uarttype = 0
> baudrate = 9600
> stopbits = 1
> databits = 8
> parity = 0
> flowcontrol = 0
> protocol = 1
>
>


Essentially something is very awkward about all of that code, and it can
definitely be simplified by using better scoping. You should consider
reading, if you haven't already,

perldoc perldsc
perldoc perllol
perldoc perlreftut
perldoc perlref

Here is a stab, untested,

#!/usr/local/bin/perl
use strict;
use warnings;


my %ports;


my $current_port = '';
while (my $line = <DATA> ) {
if ($line =~ /^port\s=\s(\d+)$/) {
$current_port = $1;
}
elsif ($line =~ /^(.*)\s=\s(.*)$/) {
die "Port not set" unless $current_port ne '';
$ports{$current_port}->{$1} = $2;
}
else {
warn "Improperly formatted line: $line";
}
}


use Data::Dumper;
print Dumper(\%ports);


__DATA__
port = 0
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol = 1
port = 1
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol = 1
John W. Krahn

2004-04-02, 8:31 pm

mgoland@optonline.net wrote:
>
> Hi all,


Hello,

> I am trying to setup a hash who's values are referance to hash's. Data
> structure should look like this
>
> hash
> 1:
> setting 1
> setting 2
> 2:
> setting 1
> setting 2
> ....
>
> I would think it can be accomplished with following code, but when I try
> to print it out it only prints the last setting which it read. Any idea's ??
>
> CODE:
> #!perl -w
> use strict;
> open RD, "input.txt";
>
> my ( $field,$portsetting, $value, $port, $portnum, %digi, $debug );
> $debug=0;
>
> while ( <RD> ) {
> if(m/^(port)\s\=\s(.*)$/i){$portnum=$2;$portnum++}
>
> $field = {};
> $digi{$portnum} = $field;
>
> m/^(.*)\s\=\s(.*)$/;
> $portsetting=$1;
> $value=$2;
> $field->{$portsetting}=$value;
>
> print "setting $portsetting -> $digi{$portnum}{$portsetting}\n" if $debug;
>
> if($portsetting eq 'porttitle'){
> $value =~ tr /-/ /;
> $value =~ m/^(\w+)\s+(\w+)/i;
> $field->{$portsetting}=$1;
> $field->{'type'}=$2;
> print "1:$digi{$portnum}{$portsetting}\t2:$digi{$portnum}{'type'}\n" if $debug;
> }
>
> }
>
> # print the whole thing
> foreach $port ( keys %digi ) {
> print "$port: { ";
> for $field ( keys %{ $digi{$port} } ) {
> print "$field=$digi{$port}{$field} ";
> }
> print "}\n";
> }
>
> Sample DATA
>
> port = 0
> bmanset = 0
> benable = 1
> uarttype = 0
> baudrate = 9600
> stopbits = 1
> databits = 8
> parity = 0
> flowcontrol = 0
> protocol = 1
> port = 1
> bmanset = 0
> benable = 1
> uarttype = 0
> baudrate = 9600
> stopbits = 1
> databits = 8
> parity = 0
> flowcontrol = 0
> protocol = 1



Perhaps this will do what you want:

#!perl -w
use strict;
use Data::Dumper;

open RD, 'input.txt' or die "Cannot open 'input.txt' $!";

my ( %data, $temp );
while ( <DATA> ) {
chomp;
my ( $name, $value ) = split /\s*=\s*/ or next;
if ( exists $temp->{ $name } or eof DATA ) {
$data{ $temp->{ port } } = $temp;
$temp = { $name, $value };
next;
}
$temp->{ $name } = $value;
}

print Dumper \%data;

__END__



John
--
use Perl;
program
fulfillment
John W. Krahn

2004-04-02, 9:30 pm

"John W. Krahn" wrote:
>
> Perhaps this will do what you want:
>
> #!perl -w
> use strict;
> use Data::Dumper;
>
> open RD, 'input.txt' or die "Cannot open 'input.txt' $!";
>
> my ( %data, $temp );
> while ( <DATA> ) {
> chomp;
> my ( $name, $value ) = split /\s*=\s*/ or next;
> if ( exists $temp->{ $name } or eof DATA ) {


Oops, forgot a line. :-)

$temp->{ $name } = $value if eof DATA;

> $data{ $temp->{ port } } = $temp;
> $temp = { $name, $value };
> next;
> }
> $temp->{ $name } = $value;
> }
>
> print Dumper \%data;
>
> __END__



John
--
use Perl;
program
fulfillment
Mark Goland

2004-04-04, 11:30 pm

John,
this code didn't work for me. Although I did have to change <DATA> to
<RD>;
----- Original Message -----
From: "John W. Krahn" <krahnj@acm.org>
To: < >
Sent: Friday, April 02, 2004 7:47 PM
Subject: Re: Hash ref's of hash's


> mgoland@optonline.net wrote:
>
> Hello,
>
Data[color=darkred]
try[color=darkred]
idea's ??[color=darkred]
$debug;[color=darkred]
$debug;[color=darkred]
>
>
> Perhaps this will do what you want:
>
> #!perl -w
> use strict;
> use Data::Dumper;
>
> open RD, 'input.txt' or die "Cannot open 'input.txt' $!";
>
> my ( %data, $temp );
> while ( <DATA> ) {
> chomp;
> my ( $name, $value ) = split /\s*=\s*/ or next;
> if ( exists $temp->{ $name } or eof DATA ) {
> $data{ $temp->{ port } } = $temp;
> $temp = { $name, $value };
> next;
> }
> $temp->{ $name } = $value;
> }
>
> print Dumper \%data;
>
> __END__
>
>
>
> John
> --
> use Perl;
> program
> fulfillment
>
> --
> To unsubscribe, e-mail: beginners-unsubscribe@perl.org
> For additional commands, e-mail: beginners-help@perl.org
> <http://learn.perl.org/> <http://learn.perl.org/first-response>
>
>



Wc -Sx- Jones

2004-04-04, 11:30 pm

Mark Goland wrote:
> John,
> this code didn't work for me. Although I did have to change <DATA> to
> <RD>;


Probably because he use the sample data in the DATA filehandle.

His code works correctly near as I can tell; so -
My question is - is your data actually in this format?
[color=darkred]


Using John's code:

#!perl -w
use strict;
use Data::Dumper;

# open RD, 'input.txt' or die "Cannot open 'input.txt' $!";

my ( %data, $temp );

while ( <DATA> ) {
chomp;
my ( $name, $value ) = split /\s*=\s*/ or next;
if ( exists $temp->{ $name } or eof DATA ) {
$data{ $temp->{ port } } = $temp;
$temp = { $name, $value };
next;
}
$temp->{ $name } = $value;
}

print Dumper \%data;

__END__
port = 0
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol = 1
port = 1
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol = 1


I get:

$VAR1 = {
'1' => {
'baudrate' => '9600',
'flowcontrol' => '0',
'uarttype' => '0',
'databits' => '8',
'stopbits' => '1',
'port' => '1',
'benable' => '1',
'parity' => '0',
'bmanset' => '0'
},
'0' => {
'protocol' => '1',
'baudrate' => '9600',
'flowcontrol' => '0',
'uarttype' => '0',
'databits' => '8',
'stopbits' => '1',
'port' => '0',
'benable' => '1',
'parity' => '0',
'bmanset' => '0'
}
};

Mark Goland

2004-04-05, 12:31 am


----- Original Message -----
From: "Wiggins d'Anconia" <wiggins@danconia.org>
To: <mgoland@optonline.net>
Cc: <beginners@perl.org>
Sent: Thursday, April 01, 2004 9:24 PM
Subject: Re: Hash ref's of hash's


> mgoland@optonline.net wrote:
Data structure should look like this[color=darkred]
>
> This does not look like a HoH, but a HoA.

Reply no, this is HoH...perhaps beter diagramed as :

NY =>
port 1 =>
setting 1
setting 2
CA =>
.....
......
>
try to print it out it only prints the last setting which it read. Any
idea's ??[color=darkred]
>
> Always check that open succeeded.
>
> open RD, "input.txt" or die "Can't open file: $!";
>
>
> Declaring all of your variables up front reduces the help that 'strict'
> can provide and generally leads to more problems. It may be that $field
> is getting reused because even though you are "emptying" it, this isn't
> clear to me.

Good point, I'll consider it

>
>
> Let's dispense with $_ it adds confusion when we should be trying to be
> explicit. Once you don't have to ask questions about references then
> consider going back to it.

This is a stylistic argument
>
> while (my $line = <RD> ) {
>
>
> Whitespace is our friend, why are we capturing a constant?

Good point, I was debuging code and didn't remove it

>
> if ($line =~ m/^port\s=\s(.*)$/i) {
> $portnum = $1;
> }
>
>
> Double assignment?

For clarity

>
>
> If we are going to capture we should double check that the string is
> formatted properly, put this into an if.
>
> if ($line =~ m/^(.*)\s=\s(.*)$/) {

Agreed...
>
> There's no real need for the temp variables but if you want them that is
> fine for readability.

I need this so I can remove any '-' in a field 'porttitle', thats is why
I do tr and create a new field TYPE. Perhaps this can be avoided with a
beter regex. I do apoligize for nto providing example in my data...will
append a new set to thread

>
>
$debug;[color=darkred]
>
> Again if you are going to run a match make sure it succeeds, especially
> when capturing. As a side note your sample data did not contain this.
>
$debug;[color=darkred]
>
> If this is just for debugging take a look at Data::Dumper it is much

easier.
>
>
> Essentially something is very awkward about all of that code, and it can
> definitely be simplified by using better scoping. You should consider
> reading, if you haven't already,
>
> perldoc perldsc
> perldoc perllol
> perldoc perlreftut
> perldoc perlref
>
> Here is a stab, untested,
>
> #!/usr/local/bin/perl
> use strict;
> use warnings;
>
>
> my %ports;
>
>
> my $current_port = '';
> while (my $line = <DATA> ) {
> if ($line =~ /^port\s=\s(\d+)$/) {
> $current_port = $1;
> }
> elsif ($line =~ /^(.*)\s=\s(.*)$/) {
> die "Port not set" unless $current_port ne '';
> $ports{$current_port}->{$1} = $2;
> }
> else {
> warn "Improperly formatted line: $line";
> }
> }
>
>
> use Data::Dumper;
> print Dumper(\%ports);
>
>
> __DATA__
> port = 0
> bmanset = 0
> benable = 1
> uarttype = 0
> baudrate = 9600
> stopbits = 1
> databits = 8
> parity = 0
> flowcontrol = 0
> protocol = 1
> port = 1
> bmanset = 0
> benable = 1
> uarttype = 0
> baudrate = 9600
> stopbits = 1
> databits = 8
> parity = 0
> flowcontrol = 0
> protocol = 1
>
> --
> To unsubscribe, e-mail: beginners-unsubscribe@perl.org
> For additional commands, e-mail: beginners-help@perl.org
> <http://learn.perl.org/> <http://learn.perl.org/first-response>
>
>


data to reflect porttitle field
port = 17
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol =
porttitle = ny1-SUN
port = 18
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol =
porttitle = ny2 -IBM
port = 19
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol =
porttitle = ny1 SUN-
port = 20
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol =
porttitle = ny1 SUN
port = 21
bmanset = 0
benable = 1
uarttype = 0
baudrate = 9600
stopbits = 1
databits = 8
parity = 0
flowcontrol = 0
protocol =
porttitle = ny1


R. Joseph Newton

2004-04-05, 1:31 am

Mark Goland wrote:

> John,
> this code didn't work for me. Although I did have to change <DATA> to
> <RD>;


What code? I see nothing above this to indicate what you are referring to.

Joseph

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com