2010-10-03 158 views
4

我有散列的数组,都具有相同的一组密钥,例如:如何从Perl中的哈希数组创建哈希散列?

my $aoa= [ 
{NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'}, 
{NAME=>'Susan', AGE=>36, SEX=>'F', ID=>, 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=>}} 
} 

注意这不仅创造了正确的密钥层次还能去除多余的,现在钥匙。

我被困在需要在其正确分层位置创建新的最内层散列的点。

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

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

所以也许我可以写一个循环,将一次添加一个级别,请从哈希是关键,比其余哈希添加到“当前”的位置,但它是一个有点麻烦,也我不知道如何保持一个“位置”的哈希散列...

+2

您预期的数据结构看起来不正确。例如,如果有两个瑞典女性,“$ expected {FEMALE} {Swedish}”应包含哪些内容?你已经显示它的方式(一路下来),这个问题没有一个好的答案。我的假设是'$ expected {FEMALE} {Swedish}'需要是一个**数组引用**,其中包含修剪后的哈希引用。 – FMc 2010-10-03 13:25:31

+0

@FM你是对的 – 2010-10-03 13:46:23

+0

这实际上不是那*很难做到的,但你必须列出一个更加定义的结构。也许用XML描述层次结构,哪些是属性/一旦出现的元素,并且可以多次列出。 – vol7ron 2010-10-03 18:55:49

回答

6
use Data::Dumper; 

my $aoa= [ 
{NAME=>'Dave', AGE=>12, SEX=>'M', ID=>123456, NATIONALITY=>'Swedish'}, 
{NAME=>'Susan', AGE=>36, SEX=>'F', ID=>, 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' =>, 
            'NAME' => 'Susan', 
            'AGE' => 36 
            } 
           ] 
       }, 
      'M' => { 
        'British' => [ 
            { 
            'ID' => 987654, 
            'NAME' => 'Bart', 
            'AGE' => 120 
            } 
           ], 
        'Swedish' => [ 
            { 
            'ID' => 123456, 
            'NAME' => 'Dave', 
            'AGE' => 12 
            } 
           ] 
       } 
     }; 

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

编辑编辑:@FM帮助。现在所有更好:D

+0

Doh,我是个白痴。我现在去修复它...:) – Amadan 2010-10-03 13:59:04

+0

Stored :: dclone可用于一般复制深层数据结构的内容。 – Ether 2010-10-03 16:07:51

+0

@Ether:谢谢你! – Amadan 2010-10-03 16:19:30

2

正如你所经历的,编写代码来创建任意深度的散列结构有点棘手。访问这些结构的代码同样很棘手。这令人惊叹:你真的想这样做吗?

更简单的方法可能是将原始信息放入数据库中。只要您关心的密钥被编入索引,数据库引擎就可以非常快速地检索感兴趣的行:向我提供SEX =女性和NATIONALITY =瑞典文的所有人。现在听起来很有希望!

您可能还会发现此感兴趣的loosely related question

+0

也许你是对的。我应该在Perl中查看一下数据库。 – 2010-10-03 18:54:27