访问 JSON 解码为哈希和哈希引用数组

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

给定以下转储程序输出是否有一种方法可以遍历每个散列以仅列出每个 results->id 记录下的项目?我希望能够说这样的话:

print $results{1342}{'domain'};

并得到语句 return testing11.com 作为结果。

我是否必须先通读所有 results 数组,然后使用 $results[$counter]{id} 访问其中的数据?我不确定如何进行。

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

您的转储显示包含一个标量的哈希引用、两个哈希引用和一个数组引用。 arrayref 具有元素的 hashrefs。如果要从中检索特定元素,则需要知道索引。

$top_level->{results}->[0]->{domain};  # is 'testing11.com'
$top_level->{results}->[0]->{status};  # is 'open'

遍历它取消引用数组

foreach my $result (@{ $top_level->{results} }) {
    print "$result->{id}\n";
}

或者您可以从所有 results 元素中获取特定键的值,例如 id

my @ids = map { $_->{id} } @{ $top_level->{results} };
say "@ids";

版画

1342 7062 432

请注意,对于包含引用的嵌套结构,您还可以使用语法

$top_level->{results}[0]{domain};  # is 'testing11.com'  

下标之间的->是可选的,参见Using References in perlref中的规则3。

当哈希键是字符串时,它们应该被引用

$top_level->{'results'}[0]{'domain'};

但是,语法快捷方式允许我们省略裸词上的引号。但是,如果 {} 中有除裸词以外的任何内容,它将被解释为表达式 并计算 。因此,如果有任何疑问,请使用引号。您希望始终保持一致的符号。

资源:教程perlreftut, reference perlref and data structures cookbook, perldsc


stevieb的回答中给出了一个直接的解决方案,创建一个反向查找。复制在这里供参考

my $results = $VAR1->{results};

my %by_ip = map {$_->{id} => $_} @$results;

print "$by_ip{1342}->{domain}\n";

您需要将内部 $results 数组转换为新的散列:

my $results = $VAR1->{results};

my %modded = map {$_->{id} => $_} @$results;

print "$modded{1342}->{domain}\n";

输出:

testing11.com

所做的是针对 @$results 中的每个散列引用,获取 id 键的值,将其设置为新散列 (%modded) 中的新键,然后将我们正在使用的整个哈希引用分配给该编号键的值。

为了完整性,TIMTOWTDI-ness 和 -Ofun 如果您使用最新的 perl (use v5.24;),带有后缀解引用(默认启用),以及对引用别名的实验性支持(use feature 'refalias';) 然后你可以取消引用 $VAR1 并将它分配给别名 (%data) 然后你可以作为常规哈希访问:

use v5.24 ;
use feature 'refaliasing';

my $VAR1 = [AS ABOVE] ;
foreach \my %data ( $VAR1->{results}->@* ) { say $data{domain} };

我喜欢这种用法(尽管在这一点上它远未被接受 "idiom"),因为您调用解引用语法 "once" - 后缀或传统形式 - 然后获取数据块内不需要使用 -> 的结构。

当然,您可以通过复制到临时散列中来做到这一点。但别名可以看作是 "more efficient and readable" (cf. Data::Alias).


更多参考资料