Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Storing an indeterminate number of hash keys in a variable

by banesong (Acolyte)
on Jul 08, 2011 at 20:33 UTC ( [id://913417]=perlquestion: print w/replies, xml ) Need Help??

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

Hello all. I have a problem that I have been bashing my head against the wall on. I have a computed hash with a very complex format (multiple layers deep). I want to be able to pick out a series of values from keys stored in this hash, and would like to be able to store the key names in an array. For example, the array would contain
my @array = ( '{title}', '{Rule}{Severity}', '{Rule}{weight}', '{Rule}{id}', '{Rule}{version}', '{Rule}{title}', '{Rule}{detailedDescription}{VulnDiscussion}', '{Rule}{detailedDescription}{Responsibility}', '{Rule}{detailedDescription}{IAControls}', '{Rule}{check}{check-content}', '{Rule}{fixtext}{content}', );
I would like to later process the array and pull individual results out of the parent hash on the fly, al la:
foreach my $firstKey (sort keys %hashData) { foreach my $arrayKey (@array) { print $hashData{$firstKey}$arrayKey; } }

With '$hashData{$firstKey}$arrayKey' being treated like '$hashData{$firstKey}{Rule}{detailedDescription}{VulnDiscussion}'.

The problem is that I don't know how deep the array key may get on the fly, and at a certain point can just write a block of code quicker for each item in the array rather than try and make it more malleable. However, I really want to make the configuration (order of items to extract, etc) more, well, configurable, and not have to add a block of code each time the group wants a new piece of data added.

Thanks in advance! T

Replies are listed 'Best First'.
Re: Storing an indeterminate number of hash keys in a variable
by wind (Priest) on Jul 08, 2011 at 21:38 UTC

    It'd be easier if you just stored the list of keys in an array ref instead of a string

    However, you could just parse the keys and traverse the data structure to find the proper value like so:

    use strict; use warnings; my @array = ( '{title}', '{Rule}{Severity}', '{Rule}{weight}', '{Rule}{id}', '{Rule}{version}', '{Rule}{title}', '{Rule}{detailedDescription}{VulnDiscussion}', '{Rule}{detailedDescription}{Responsibility}', '{Rule}{detailedDescription}{IAControls}', '{Rule}{check}{check-content}', '{Rule}{fixtext}{content}', ); for my $firstKey (sort keys %hashData) { for my $arrayKey (@array) { my $val = $hashData{$firstKey}; # Traverse to desired value $val = $val{$1} while $arrayKey =~ /\{(.*?)\}/g; print $val, "\n"; } }
      Thanks; that looks like it will work. Just curious, what do you mean store it as an array ref, or more importantly, why would it be better?

      I realize that a bit more background might be useful; I am post processing a bunch of gigantic, complex XML files. The reason for the strings at the moment is to allow users to alter the the tagged output without my intervention. It is hard enough trying to explain the naming convention of XML and how to annotate it, let alone try and get them to understand Perl data structures/syntax. T

Re: Storing an indeterminate number of hash keys in a variable
by planetscape (Chancellor) on Jul 08, 2011 at 21:58 UTC
Re: Storing an indeterminate number of hash keys in a variable
by state-o-dis-array (Hermit) on Jul 08, 2011 at 20:51 UTC
    There's probably a better way to do it, but you could do something along the lines of:
    my %test; $test{a}{b}{c}{d} = "Hi"; my @keys = qw( a b c d ); my $out; my $ref = \%test; for( @keys ){ if( ref $ref->{$_} eq 'HASH' ){ $ref = \%{$ref->{$_}}; } else{ $out = $ref->{$_}; } } print "$out\n";
Re: Storing an indeterminate number of hash keys in a variable
by tj_thompson (Monk) on Jul 08, 2011 at 22:34 UTC

    This feels like the wrong solution to the problem as the results are very messy. This seems like a good situation for a struct type solution:

    use strict; use warnings; # make a little mini class for your records use Class::Struct Record => [title => '$', rule_severity => '$', rule_ +weight => '$' ]; my %data_hash = (); my @data_array = (); $data_hash{first_key} = new Record; $data_hash{second_key} = new Record; # instead of pushing a text string of keys, just push field to access push(@data_array, 'title'); push(@data_array, 'rule_weight'); # some code later changes the hash $data_hash{first_key}->title('Mr. President'); $data_hash{first_key}->rule_weight(100); $data_hash{second_key}->title('Emperor'); $data_hash{second_key}->rule_weight(1000); # want to access it from your array for my $key (sort keys %data_hash) { for my $field (@data_array) { print "My data is (".$data_hash{$key}->$field.")\n"; } }

    Output:

    C:\tmp>tmp.pl My data is (Mr. President) My data is (100) My data is (Emperor) My data is (1000)
      Wish you could edit comments :) I mean that storing the keys of a hash seems messy, thus the struct solution.

        In fact you can. Just click on the title of your reply (or this link, in this case), scroll down until you see the text box, edit its content, hit the update button and you're done. It's as simple as it sounds :)

        Edit:To prove my point, and to also contribute my two cents to the discussion at hand, wind's solution above is along the lines of what I would've tried.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-04-18 19:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found