将数组中的每个元素添加到Perl中的复杂哈希中

时间:2015-04-07 16:57:29

标签: perl

我有一个包含n个元素的数组。我想将每个元素添加到复杂的哈希中,每个哈希都作为键/值对。如果元素的数量是固定的,比方说三,我会这样做:

my %hash;
my @array = ("first", "second", "third");
$hash{$array[0]}{$array[1]}{$array[2]}++;

我最终想要的结构是(用Data :: Dumper打印):

$VAR1 = 'first';
$VAR2 = {
        'second' => {
                   'third' => 1
};

但是当数组中的元素数量不固定时,我无法实现相同的结构。带有匿名变量并迭代数组的东西,是的,但像

foreach @array{$hash{$_}++};
之类的东西显然只会为每个元素创建一个条目,而不是所需的结构。帮助?

2 个答案:

答案 0 :(得分:4)

这样的东西可以构建你想要的N个元素的结构:

use strict;
use warnings; 

use Data::Dumper;
my @array = qw(first second third four five six seven);

my $hash;
foreach my $key ( reverse @array ) {
   $hash = { $key => $hash };
}
print Dumper $hash;

__END__
$VAR1 = {
      'first' => {
                   'second' => {
                                 'third' => {
                                              'fourth' => {
                                                          'fifth' => {
                                                                      'sixth' => {
                                                                                 'seventh' => undef
                                                                               }
                                                                    }
                                                        }
                                            }
                               }
                 }
    };

目前还不清楚你真正需要的是什么。如果您再解释一下您的用例,可能会有更好的解决方案。增加这种结构似乎并不容易。

稍微玩一下后,您可以通过遍历底部的哈希引用然后递增最后一个元素的值来增加。虽然它不是很漂亮:|

# incrementing
my $elem = $hash; # copy the reference 
foreach my $key ( @array ) {
   # found the bottom of the hash
   unless ( $elem->{$key} && ref($elem->{$key}) ) { 
      $elem->{$key}++;
      last; 
   }

   # not at the bottom, move to the next level
   $elem = $elem->{$key};
}
print Dumper $hash;

__END__
$VAR1 = {
      'first' => {
                   'second' => {
                                 'third' => {
                                              'fourth' => {
                                                            'fifth' => {
                                                                         'sixth' => {
                                                                                      'seventh' => 1
                                                                                    }
                                                                       }
                                                          }
                                            }
                               }
                 }
    };

答案 1 :(得分:3)

如果您维护当前哈希引用,则相对简单。这个简短的程序演示了

前几步确保每个哈希元素都存在且其值是哈希引用。 $href在每个阶段都被移动到下一级哈希。对于数组的最后一个元素,最新的哈希级别元素会增加,而不是设置为哈希引用。

这个数据结构是否正确选择取决于你构建它之后还需要做什么呢

use strict;
use warnings;

my %hash;
my @array = qw/ first second third fourth fifth /;

drill_hash(\%hash, @array);

use Data::Dump;
dd \%hash;

sub drill_hash {
  my ($href, @list) = @_;
  my $final = pop @list;
  $href = $href->{$_} //= {} for @list;
  ++$href->{$final};
}

<强>输出

{
  first => { second => { third => { fourth => { fifth => 1 } } } },
}

<强>更新

了解了你的目的后,保持ngrams出现次数的最简单方法是使用一个特殊的散列键来保存到目前为止的单词序列的 count

此程序使用该键的值_COUNT,您可以看到,{under}{a}{_COUNT}{under}{a}{rock}{_COUNT}都是1

use strict;
use warnings;

my %counts;

count_ngram(\%counts, qw/ under a /);
count_ngram(\%counts, qw/ a rock /);
count_ngram(\%counts, qw/ under a rock /);
count_ngram(\%counts, qw/ a tree /);
count_ngram(\%counts, qw/ under a tree /);

use Data::Dump;
dd \%counts;

sub count_ngram {
  my ($href, @ngram) = @_;
  my $final = pop @ngram;
  $href = $href->{$_} //= {} for @ngram;
  ++$href->{$final}{_COUNT};
}

<强>输出

{
  a => { rock => { _COUNT => 1 }, tree => { _COUNT => 1 } },
  under => {
    a => { _COUNT => 1, rock => { _COUNT => 1 }, tree => { _COUNT => 1 } },
  },
}