Perl循环遍历单个元素的数组哈希

时间:2012-07-28 23:43:33

标签: arrays perl loops hash

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

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 个答案:

答案 0 :(得分: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";

答案 1 :(得分:2)

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

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

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)

答案 2 :(得分: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);

答案 3 :(得分:0)

这是一种更为谨慎(不一定更好)的做事方式。除非维护代码的人知道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;