Accessing JSON decoded into a HASH and an array of hash references

∥☆過路亽.° 提交于 2019-12-08 01:59:52

问题


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
                          }]
      }

回答1:


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";



回答2:


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.




回答3:


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


来源:https://stackoverflow.com/questions/37845433/accessing-json-decoded-into-a-hash-and-an-array-of-hash-references

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!