Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Help with hash/array data structure

by robinbowes (Beadle)
on Nov 11, 2003 at 17:08 UTC ( [id://306269]=perlquestion: print w/replies, xml ) Need Help??

robinbowes has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am successfully using the following data structures:
# List all packet types that this script knows about my %Idents = ( Rotation_Marker => 0x90, Format_7 => 0x87, ); # List packet lengths of each of the packet types (Ident char to check +sum, inclusive) my %Packet_Length = ( $Idents{ Rotation_Marker } => 30, $Idents{ Format_7 } => 28, ); # unpack templates to use for each packet type (not including the pack +et Ident) my %packet_template = ( $Idents{ Rotation_Marker } => "C3 n n n n n n n n n n n n C3", $Idents{ Format_7 } => "C B16 n2 A4 A8 A2 A A A3 C2", );
So far so good. I can read an ident from a file and then use construct like $packet_template{ $ident } I am also using the following data structures:
my @packet_fields = qw( ident flags x y mode3 callsign route spare1 spare2 flight_level terminator chksum ); my @rotation_packet_fields = qw(ident RDP_Ident Radar_Site_Ident site_x site_y Useful_Vol_Upper Useful_Vol_Lower Useful_Vol_North Useful_Vol_South Useful_Vol_East Useful_Vol_West Rotation Rotation_x Rotation_y Reserved QNH_Datum terminator chksum );
I use these as follows:
if ($ident == $Idents{ Rotation_Marker }) { @packet{ @rotation_packet_fields } = unpack ( $packet_template{ $ident }, $buffer); ... if ($ident == $Idents{ Format_7 }) { @packet{ @packet_fields } = unpack ( $packet_template{ $ident }, $buffer);
Now, what I'd like to do is to create a hash of these arrays and refer to them in a similar fashion to the way I refer to the %packet_template hash. However, I can't work out how to do it. I've come up with the following declaration to create the hash, but I don't know how to re-reference it:
my %packet_fields = ( $Idents{ Format_7 } => qw( ident flags x y mode3 callsign route spare1 spare2 flight_level terminator chksum ), $Idents{ Format_7 } => qw(ident RDP_Ident Radar_Site_Ident site_x site_y Useful_Vol_Upper Useful_Vol_Lower Useful_Vol_North Useful_Vol_South Useful_Vol_East Useful_Vol_West Rotation Rotation_x Rotation_y Reserved QNH_Datum terminator chksum ), );
Is this correct? How do I use it in my code, e.g. this doesn't work:
@packet{$%packet_fields{ $ident} } = unpack ( $packet_template{ $ident }, $buffer);
What should I use? Thanks, R.
-- Robin Bowes | http://robinbowes.com

Replies are listed 'Best First'.
Re: Help with hash/array data structure
by princepawn (Parson) on Nov 11, 2003 at 17:24 UTC

    This

    my %packet_fields = ( $Idents{ Format_7 } => qw( ident flags x ...
    Should be:
    my %packet_fields = ( $Idents{ Format_7 } => [qw( ident flags x ...]
    Likewise, this:
    $Idents{ Format_7 } => qw(ident RDP_Ident Radar_Site_Ident site_x
    Should be this:
    $Idents{ Format_7 } => [qw(ident RDP_Ident Radar_Site_Ident site_x ... ]
    The value of a key must be a scalar or *reference* to an array or hash, not an actual array or hash, as you had in your code. Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality
Re: Help with hash/array data structure
by injunjoel (Priest) on Nov 11, 2003 at 18:39 UTC
    Greetings all,
    Nested data structures will most definitely make you life easier... I suggest getting the book Advanced Perl Programming and reading the chapter on complex data structures. Also have a look at this node for a nutshell version of nested data types.
    All that being said the one helpful (hopefully) piece of advice I would give you in working with this area of perl is, Always check your data. Personally I use Dumpvalue others around here tout Data::Dumper, the choice is yours.
    Here is how I check my stuff.
    use strict; #Always use Dumpvalue; ###just an example of nested data my @example = ( {'firstname'=>'Justin', 'lastname'=>'Tyme', 'Age'=>'21'}, {'firstname'=>'Ima', 'lastname'=>'Geek','Age'=>'21'} ); dump_ref(\@example);###you need to pass a reference to your data since + the dumpValues method only takes references. sub dump_ref { my $ref = shift; my $dumper = new Dumpvalue; $dumper->dumpValues($ref); } ___OUTPUT___ 0 ARRAY(0x80628f0) 0 HASH(0x804c8d4) 'Age' => 21 'firstname' => 'Justin' 'lastname' => 'Tyme' 1 HASH(0x80628b4) 'Age' => 21 'firstname' => 'Ima' 'lastname' => 'Geek'
    So that gets you some of the way there as far as creating data and seeing what it is actually doing.
    Now getting it back out! This is where I got the most tripped up. Just keep in mind that you must reference (or dereference in this case) the data in the form you will eventually be useing it.
    So, if you want to get the firstname of the person in the second element of the array above it would be:
    $example[1]->{firstname};
    or if you wanted to get all the keys for the hash in the first element of the array you would use:
    my @first_elm_keys = keys %{$example[0]};
    Of course like with anything in perl there is more than one way to do it. I personally like the arrow dereferencing scheme. It just makes more sense to me, looks like its pointing to the data.
    Hope that helps
    -injunjoel
Re: Help with hash/array data structure
by shockme (Chaplain) on Nov 11, 2003 at 17:23 UTC
    Unless I've misread the above, you're wanting to store the array as a hash element. If so, the following should illustrate one way to do it:
    my @array = qw (ident RDP_Ident Radar_Site_Ident site_x site_y Useful_Vol_Upper Useful_Vol_Lower Useful_Vol_North Useful_Vol_South Useful_Vol_East Useful_Vol_West Rotation Rotation_x Rotation_y Reserved QNH_Datum terminator chksum ); my %Idents; $Idents{ Format_7 } = \@array; foreach my $element (@{$Idents{ Format_7 }}) { print "$element\n"; }

    If things get any worse, I'll have to ask you to stop helping me.

Re: Help with hash/array data structure
by duff (Parson) on Nov 11, 2003 at 18:17 UTC
    Here's some syntax that might start you off:
    $hash{$key} = [ qw(foo bar baz) ]; # The [ ] make an anonymous array + reference print "@{$hash{$key}}\n"; # output the whole array print $hash{$key}->[0], "\n"; # output an individual element of + an array
    See perlref, perldsc, and perllol for more info.
Re: Help with hash/array data structure
by Roy Johnson (Monsignor) on Nov 11, 2003 at 17:45 UTC
    You've muddled your thinking about references and dereferencing.
    my %packet_fields = ( $Idents{ Format_7 } => qw( ident flags
    Here, you're trying to use an array (qw(...)) where you can only put a scalar. What you want is an array reference:[qw(...)]

    I'm not entirely clear on what you're hoping for here: $%packet_fields{ $ident} , but you can bet that $% is not going to be a useful combination of sigils. It's probably parsed as a special variable followed by a bareword and panic.

    When in doubt, use the general form of dereferencing, which is the sigil you would use if you had an ordinary variable, then a curly-wrapped expression returning a rereference, and then any indexing you would use on an ordinary variable of the referenced type. You can nest these as deeply as you need to.

    Check out perldoc perlreftut again.

Re: Help with hash/array data structure
by Art_XIV (Hermit) on Nov 11, 2003 at 18:48 UTC

    References are a big spicy meatball! And, of course, there's more than one way to do it.

    The following snippet might help:

    use strict; my %packet_fields = ( 'Format_X' => ['ident', 'flags', 'x', 'y', 'mode3'], 'Format_Y' => ['ident', 'RDP_Ident', 'Radar_Site_Ident', 'site_x'] ); foreach my $format (keys %packet_fields) { foreach my $field (@{$packet_fields{$format}}) { #line 9 print "$format -> $field\n"; } } foreach my $format (keys %packet_fields) { print "$format's 2nd field = ", $packet_fields{$format}->[1], "\n"; +#line 15 print "$format's 3rd field = ", $packet_fields{$format}[2], "\n"; #l +ine 16 }

    In this sample, %packet_fields is a regular old hash. The keys for this hash are garden-variety scalars. The value associated w/ each key is a reference to an anonymous (unnamed) array. These two anon. arrays are the only references that we have to deal with, and the only things that require any dereferencing syntax.

    The @{} in line 9 is using a form of dereferencing notation to give me an array.

    There's another form of dereferencing that I can use, too, as seen in lines 15 and 16.

    Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"
      Hi, Thanks for all the replies - most informative!

      I've now got working code, something like this:

      # Declaration of the data structure my %packet_fields = ( $Idents{ Format_7 } => [qw( ident x y flight_level chksum )], $Idents{ Rotation_Marker } => [qw( ident site_x site_y chksum )], ); # This structure listed for completeness of this example! my %packet_template = ( $Idents{ Rotation_Marker } => "C3 n n n n n n n n n n n n C3", $Idents{ Format_7 } => "C B16 n2 A4 A8 A2 A A A3 C2 +", ); # Referencing the data structure # code here to read $buffer from STDIN # $ident is extracted from $buffer @packet{ @{$packet_fields{ $ident }} } = unpack ( $packet_template{ $ident }, $buffer);
      I've got one further question about creating and accessing a hash of hashes.

      I'm currently using the following structures:

      my %ARP_GLA = ( x => 247866.9, y => 666999.7, ); my %ARP_EDI = ( x => 314382.0, y => 673841.9,
      I'd like to combine these into one data structure which I guess is a hash of hashes.

      I believe I know enough to create the hash. This should do the trick:

      my %ARP = ( GLA => { x => 247866.9, y => 666999.7 }, EDI => { x => 314382.0, y => 673841.9 } );
      How do I now access the elements in this structure?

      Is it something like:

      my $edi_arp = $ARP{EDI}->{x};
      Thanks.

      R.

      --
      Robin Bowes | http://robinbowes.com

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://306269]
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (3)
As of 2024-04-24 02:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found