Given the following dumper output is there a way to iterate through each hash to list only the items under each results->id
record? I want to be able to say things like:
print $results{1342}{'domain'};
and have the statement return testing11.com
as a result.
Would I have to first read through all of results
array and then use $results[$counter]{id}
to access the data in there ? I'm not sure how to proceed.
$VAR1 = {
'end_time' => 1466017739,
'options' => {
'hour_offset' => '00',
'timezone' => 'America/New_York'
},
'field_headers' => {
'priority' => 'Priority',
'status' => 'Status',
'assignee_external_id' => 'Assignee external id',
'initially_assigned_at' => 'Initially assigned at'
},
'results' => [
{
'priority' => 'High',
'status' => 'Open',
'domain' => 'testing11.com',
'generated_timestamp' => 1546547669,
'id' => 1342
},
{
'priority' => 'Low',
'status' => 'Open',
'domain' => 'testing22.com',
'generated_timestamp' => 1464567669,
'id' => 7062
},
{
'priority' => 'Low',
'status' => 'Closed',
'domain' => 'testing33.com',
'generated_timestamp' => 1464267669,
'id' => 432
}]
}
Your dump shows a hashref containing a scalar, two hashrefs, and an arrayref. The arrayref has hashrefs for elements. If you want to retrieve specific elements from it, you need to know the index.
$top_level->{results}->[0]->{domain}; # is 'testing11.com'
$top_level->{results}->[0]->{status}; # is 'open'
To iterate through it dereference the array
foreach my $result (@{ $top_level->{results} }) {
print "$result->{id}\n";
}
Or you can just get values from all results
elements for a particular key, say for id
my @ids = map { $_->{id} } @{ $top_level->{results} };
say "@ids";
Prints
1342 7062 432
Note that with nested structures, which contain references, you can also use syntax
$top_level->{results}[0]{domain}; # is 'testing11.com'
The ->
is optional between subscripts, see rule 3. in Using References in perlref.
When the hash keys are strings they should be quoted
$top_level->{'results'}[0]{'domain'};
However, a syntax shortcut allows us to omit quotes on barewords. But if there is anything other than a bareword inside {}
it will be interpreted as an expression and evaluated. So if in any doubt use quotes. You want consistent notation throughout.
Resources: Tutorial perlreftut, reference perlref and data structures cookbook, perldsc.
A direct solution is given in stevieb's answer, creating a reverse lookup. Copied here for reference
my $results = $VAR1->{results};
my %by_ip = map {$_->{id} => $_} @$results;
print "$by_ip{1342}->{domain}\n";
You need to transform the inner $results
array into a new hash:
my $results = $VAR1->{results};
my %modded = map {$_->{id} => $_} @$results;
print "$modded{1342}->{domain}\n";
Output:
testing11.com
What that does is for each hash reference inside @$results
, takes the value of the id
key, sets it as a new key inside of a new hash (%modded
), and then assigns the whole hash ref we're working with to the value of that numbered key.
For completeness, TIMTOWTDI-ness and -Ofun
if you use the latest perl (use v5.24;
), with postfix dereferencing (enabled by default), and experimental support for reference aliasing (use feature 'refalias';
) then you can dereference $VAR1
and assign it to an alias (%data
) which you can then access as a regular hash:
use v5.24 ;
use feature 'refaliasing';
my $VAR1 = [AS ABOVE] ;
foreach \my %data ( $VAR1->{results}->@* ) { say $data{domain} };
I like this usage (though at this point it is far from an accepted "idiom") because you invoke the dereferencing syntax "once" - either the postfix or traditional form - and then get a data structure where it is not necessary to use ->
inside the block .
Of course you can do this by copying into a temporary hash. but aliasing can be seen as "more efficient and readable" (cf. Data::Alias
).
Further References:
- The Perl Data Structures Cookbook documentation that comes with perl (
perldoc perldsc
in your shell)
- An accessible PerlTricks article on references.
- brian d foy's introduction to
use feature 'refalias'
and the perldelta
entry for the feature for version 5.22