如何从 Perl 中的哈希数组创建哈希的哈希?

发布于 2024-09-26 01:43:56 字数 1101 浏览 3 评论 0原文

我有一个散列数组,全部具有相同的键集,例如:

my $aoa= [
 {NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'},
 {NAME=>'Susan', AGE=>36, SEX=>'F', ID=>543210, NATIONALITY=>'Swedish'},
 {NAME=>'Bart', AGE=>120, SEX=>'M', ID=>987654, NATIONALITY=>'British'},
]

我想编写一个子例程,使用给定的键层次结构将其转换为散列的散列:

my $key_hierarchy_a = ['SEX', 'NATIONALITY'];
aoh_to_hoh ($aoa, $key_hierarchy_a) = @_;
 ...
}

将返回

{M=>
  {Swedish=>{{NAME=>'Dave', AGE=>12, ID=>123456}},
   British=>{{NAME=>'Bart', AGE=>120, ID=>987654}}}, 
 F=>
  {Swedish=>{{NAME=>'Susan', AGE=>36,  ID=>543210}}
}

注意这不仅创建正确的键层次结构还要删除现在多余的键。

我陷入了需要在正确的分层位置创建新的、最内部的哈希的境地。

问题是我不知道“深度”(即键的数量)。如果我有一个常数,我可以这样做:

%h{$inner_hash{$PRIMARY_KEY}}{$inner_hash{$SECONDARY_KEY}}{...} = filter_copy($inner_hash,[$PRIMARY_KEY,$SECONDARY_KEY])

所以也许我可以编写一个循环,一次添加一个级别,从散列中删除该键,然后将剩余的散列添加到“当前”位置,但它是有点麻烦,而且我不知道如何在哈希值的哈希值中保留“位置”......

I have an array of hashes, all with the same set of keys, e.g.:

my $aoa= [
 {NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'},
 {NAME=>'Susan', AGE=>36, SEX=>'F', ID=>543210, NATIONALITY=>'Swedish'},
 {NAME=>'Bart', AGE=>120, SEX=>'M', ID=>987654, NATIONALITY=>'British'},
]

I would like to write a subroutine that will convert this into a hash of hashes using a given key hierarchy:

my $key_hierarchy_a = ['SEX', 'NATIONALITY'];
aoh_to_hoh ($aoa, $key_hierarchy_a) = @_;
 ...
}

will return

{M=>
  {Swedish=>{{NAME=>'Dave', AGE=>12, ID=>123456}},
   British=>{{NAME=>'Bart', AGE=>120, ID=>987654}}}, 
 F=>
  {Swedish=>{{NAME=>'Susan', AGE=>36,  ID=>543210}}
}

Note this not only creates the correct key hierarchy but also remove the now redundant keys.

I'm getting stuck at the point where I need to create the new, most inner hash in its correct hierarchical location.

The problem is I don't know the "depth" (i.e. the number of keys). If I has a constant number, I could do something like:

%h{$inner_hash{$PRIMARY_KEY}}{$inner_hash{$SECONDARY_KEY}}{...} = filter_copy($inner_hash,[$PRIMARY_KEY,$SECONDARY_KEY])

so perhaps I can write a loop that will add one level at a time, remove that key from the hash, than add the remaining hash to the "current" location, but it's a bit cumbersome and also I'm not sure how to keep a 'location' in a hash of hashes...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感性不性感 2024-10-03 01:43:56
use Data::Dumper;

my $aoa= [
 {NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'},
 {NAME=>'Susan', AGE=>36, SEX=>'F', ID=>543210, NATIONALITY=>'Swedish'},
 {NAME=>'Bart', AGE=>120, SEX=>'M', ID=>987654, NATIONALITY=>'British'},
];

sub aoh_to_hoh {
  my ($aoa, $key_hierarchy_a) = @_;
  my $result = {};
  my $last_key = $key_hierarchy_a->[-1];
  foreach my $orig_element (@$aoa) {
    my $cur = $result;
    # song and dance to clone an element
    my %element = %$orig_element;
    foreach my $key (@$key_hierarchy_a) {
      my $value = delete $element{$key};
      if ($key eq $last_key) {
        $cur->{$value} ||= [];
        push @{$cur->{$value}}, \%element;
      } else {
        $cur->{$value} ||= {};
        $cur = $cur->{$value};
      }
    }
  }
  return $result;
}

my $key_hierarchy_a = ['SEX', 'NATIONALITY'];
print Dumper(aoh_to_hoh($aoa, $key_hierarchy_a));

根据@FM 的评论,您确实需要一个额外的数组级别。

输出:

$VAR1 = {
          'F' => {
                   'Swedish' => [
                                  {
                                    'ID' => 543210,
                                    'NAME' => 'Susan',
                                    'AGE' => 36
                                  }
                                ]
                 },
          'M' => {
                   'British' => [
                                  {
                                    'ID' => 987654,
                                    'NAME' => 'Bart',
                                    'AGE' => 120
                                  }
                                ],
                   'Swedish' => [
                                  {
                                    'ID' => 123456,
                                    'NAME' => 'Dave',
                                    'AGE' => 12
                                  }
                                ]
                 }
        };

编辑:哦,顺便说一句 - 如果有人知道如何优雅地克隆参考内容,请教。谢谢!

编辑编辑:@FM 帮助了。现在好多了 :D

use Data::Dumper;

my $aoa= [
 {NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'},
 {NAME=>'Susan', AGE=>36, SEX=>'F', ID=>543210, NATIONALITY=>'Swedish'},
 {NAME=>'Bart', AGE=>120, SEX=>'M', ID=>987654, NATIONALITY=>'British'},
];

sub aoh_to_hoh {
  my ($aoa, $key_hierarchy_a) = @_;
  my $result = {};
  my $last_key = $key_hierarchy_a->[-1];
  foreach my $orig_element (@$aoa) {
    my $cur = $result;
    # song and dance to clone an element
    my %element = %$orig_element;
    foreach my $key (@$key_hierarchy_a) {
      my $value = delete $element{$key};
      if ($key eq $last_key) {
        $cur->{$value} ||= [];
        push @{$cur->{$value}}, \%element;
      } else {
        $cur->{$value} ||= {};
        $cur = $cur->{$value};
      }
    }
  }
  return $result;
}

my $key_hierarchy_a = ['SEX', 'NATIONALITY'];
print Dumper(aoh_to_hoh($aoa, $key_hierarchy_a));

As per @FM's comment, you really want an extra array level in there.

The output:

$VAR1 = {
          'F' => {
                   'Swedish' => [
                                  {
                                    'ID' => 543210,
                                    'NAME' => 'Susan',
                                    'AGE' => 36
                                  }
                                ]
                 },
          'M' => {
                   'British' => [
                                  {
                                    'ID' => 987654,
                                    'NAME' => 'Bart',
                                    'AGE' => 120
                                  }
                                ],
                   'Swedish' => [
                                  {
                                    'ID' => 123456,
                                    'NAME' => 'Dave',
                                    'AGE' => 12
                                  }
                                ]
                 }
        };

EDIT: Oh, BTW - if anyone knows how to elegantly clone contents of a reference, please teach. Thanks!

EDIT EDIT: @FM helped. All better now :D

始终不够 2024-10-03 01:43:56

正如您所经历的,编写代码来创建任意深度的哈希结构有点棘手。访问此类结构的代码同样棘手。这让人想知道:您真的想这样做吗?

一种更简单的方法可能是将原始信息放入数据库中。只要您关心的键已建立索引,数据库引擎就能够非常快速地检索感兴趣的行:给我所有 SEX = 女性且 NATIONALITY = 瑞典人。现在听起来很有希望!

您可能还会发现这个 松散相关的问题感兴趣。

As you've experienced, writing code to create hash structures of arbitrary depth is a bit tricky. And the code to access such structures is equally tricky. Which makes one wonder: Do you really want to do this?

A simpler approach might be to put the original information in a database. As long as the keys you care about are indexed, the DB engine will be able to retrieve rows of interest very quickly: Give me all persons where SEX = female and NATIONALITY = Swedish. Now that sounds promising!

You might also find this loosely related question of interest.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文