perl 访问数组和散列的存储嵌套层中的数据

wdebmtf2  于 2023-03-30  发布在  Perl
关注(0)|答案(3)|浏览(167)

我有以下数据结构,它将数据存储在数组和哈希的组合中:

$data = [
          {
            'foo' => {
                       'lang' => 'en',
                       'contact' => [
                                      {
                                        'email' => 'foo@example.org'
                                      },
                                      {
                                        'phone' => '2125551212'
                                      }
                                    ],
                       'browser' => 'firefox'
                     }
          },
          {
            'bar' => {
                       'lang' => 'fr',
                       'contact' => [
                                      {
                                        'email' => 'bar@example.com'
                                      },
                                      {
                                        'phone' => '9125551212'
                                      }
                                    ],
                       'browser' => 'lynx'
                     }
          }
        ];

我怎样才能得到一个包含bar的email的字符串呢?可能会有额外的数据,所以使用硬编码的数组索引访问任何东西都不起作用。
我使用grep的各种组合进行了实验,但由于数据嵌套的方式,没有取得太大的成功。

pqwbnv8z

pqwbnv8z1#

“第一,严惩那个构建结构的人,你的真实的数据里可能有更多的东西,但我在现实生活中也见过这种笨拙的结构。”
遍历数据结构以找到联系人。首先,找到具有所需密钥的哈希:

my $key = 'bar';
my @hashes =
    map { exists $_->{$key} ? $_->{$key} : () } $data->@*;

现在有点麻烦了,因为$contact是一个哈希数组,其中只有一个(或者可能少于所有)哈希值有你需要的东西。你需要检查每个哈希值,所以你必须扁平化这个列表(这真的很烦人):

my @contact_hashes =
    map { exists $_->{contact} ? $_->{contact}->@* : ()  }
    @hashes;

以上是所有带有email键的哈希值。现在提取值:

my @email = map { $_->{email} } @contact_hashes;

你可以用不同的方法把它们组合在一起,以摆脱临时值:

my @email =
    map { exists $_->{email} ? $_->{email} : () }
    map { exists $_->{contact} ? $_->{contact}->@* : ()  }
    map { exists $_->{$key} ? $_->{$key} : () }
    $data->@*;

这是我在Intermediate Perl中介绍的内容,但Perl Data Structures Cookbook也很好。

1dkrff03

1dkrff032#

这将找到所有的“酒吧”和他们所有的“电子邮件”

no autovivification;
print
  map {
    map { $_->{email} // () }
      @{ $_->{bar}{contact} // [] }
    } @$data;

需要模块自动激活以避免使用新元素破坏数据。
最好把你的数据重组成一些直接的、不那么危险的东西。特别是当你需要很多查找的时候。

d8tt03nd

d8tt03nd3#

这里有一个简短的方法,可以避免自动激活,而不依赖于CPAN模块,如autovivificationData::Diver

# ------ short version
@emails =
  map { $_->{email} // () }
  map { @{ $_->{contact} // [] } }
  map { $_->{bar} // () }
  @$data;

或更长的版本,强调这背后的原则

# ------ long symmetrical version
@emails =
  map { $_->{email} // () }
  map { @$_ }
  map { $_->{contact} // () }
  map { $_->{bar} // () }
  map { @$_ }
  $data;

再次...请注意,您的数据的可疑结构不能保证只有一个“栏”,每个“栏”只有一个“电子邮件”。
因此,你的结果集必须是一个数组@电子邮件。

相关问题