3

我有一个数组哈希,如图所示:

my %hash = (
  234 => ["aa", "bb", "aa", "ab", "aa"],
  235 => ["aa", "ab", "aa", "bb", "aa"],
  236 => ["bb", "aa", "aa", "aa", "bb"],
  ...
)

我正在尝试遍历每个值的第一个元素并计算bb.

例如,在上面的哈希中,我对bb显示的所有第一个元素都出现了一次。我需要将该数字(所有数组的第 0 个元素中的“bb”数)推入一个新数组,然后移动到下一组元素。

对于上面的示例,我将遍历数组的所有 4 个元素并获得一个带有(1, 1, 0, 1, 1).

我在正确编写代码时遇到了很多麻烦,还没有找到类似的问题。任何帮助将非常感激。

4

4 回答 4

5

一个简单的解决方案:迭代哈希值。对于每个值,遍历数组的成员并在需要时将 1 添加到结果数组:

#!/usr/bin/perl
use warnings;
use strict;

my %hash = (234 => [qw/aa bb aa ab aa/],
            235 => [qw/aa ab aa bb aa/],
            236 => [qw/bb aa aa aa bb/],
           );

my @result;

for my $value (values %hash) {
    my $i = 0;
    for (@$value) {
        $result[$i++] += 'bb' eq $_;
    }
}

print "@result\n";
于 2012-07-29T00:02:23.070 回答
2

grep运算符是计算列表中符合特定条件的值的最佳工具。只需遍历哈希值列表的每个条目即可获得每个元素的计数。

此代码假定每个哈希值数组具有相同的长度,并使用第一个元素的长度作为所有它们的大小。

use strict;
use warnings;

my %data = (
  234 => [ qw/aa bb aa ab aa/ ],
  235 => [ qw/aa ab aa bb aa/ ],
  236 => [ qw/bb aa aa aa bb/ ],
);

my @count_bb;
for my $i ( 0 .. $#{(values %data)[0]} ) {
  $count_bb[$i] = grep { $_->[$i] eq 'bb' } values %data;
} 

print "@count_bb\n";

输出

1 1 0 1 1

此替代方法将创建一个散列,其中包含散列值数组中每个不同值的计数。第一步初始化散列以在每个元素中具有正确数量的零,第二步增加数据中遇到的每个值的计数,最后循环打印结果%counts散列的内容。

use strict;
use warnings;

my %data = (
  234 => [ qw/aa bb aa ab aa/ ],
  235 => [ qw/aa ab aa bb aa/ ],
  236 => [ qw/bb aa aa aa bb/ ],
);

my %counts;
$counts{$_} = [ (0) x @{(values %data)[0]} ] for map @$_, values %data;

for my $i ( 0 .. $#{(values %data)[0]} ) {
  $counts{$_}[$i]++ for map $_->[$i], values %data;
} 

while (my ($k, $v) = each %counts) {
    printf "%s => (%s)\n", $k, join ', ', @$v;
}

输出

ab => (0, 1, 0, 1, 0)
bb => (1, 1, 0, 1, 1)
aa => (2, 1, 3, 1, 2)
于 2012-07-29T05:31:35.183 回答
0
use Data::Dumper;

%hash = (234 => [aa, bb, aa, ab, aa],
         235 => [aa, ab, aa, bb, aa],
         236 => [bb, aa, aa, aa, bb],
        );

do { $i = 0; $element{$i++}->{$_}++ for @{$_}; } for (values %hash);

print Dumper(\%element);
于 2012-07-29T02:58:26.363 回答
0

这是一种更加 perl-ish(不一定更好)的做事方式。除非那些维护代码的人非常了解 perl,否则它会不太清楚。尽管如此,学习 map 和 grep 并不是一个坏主意。一旦你熟悉了它们,它们可以帮助你的代码的意图更加清晰。我建议查看每个解决方案并尝试弄清楚每个解决方案的工作原理。

此解决方案将处理太短的数组,尽管这可能是也可能不是您正在寻找的内容,具体取决于应用程序。

use warnings;
use strict;

use Data::Dumper;

my %hash = (
    '234' => [qw(aa bb aa ab aa)],
    '235' => [qw(aa ab aa bb aa)],
    '236' => [qw(bb aa aa aa bb)],
);

my @result = ();

while ( grep {scalar @{$_}} values %hash ) {
    push @result, scalar @{[
        grep {$_ eq 'bb'}
            map {shift @{$_}}
                values %hash
    ]};
}

print Dumper \@result;
于 2012-07-29T04:43:28.140 回答