我有一个散列,其值是数组。我需要找到那些数组的常见元素, 即。所有数组中都存在的元素。所以我将哈希的值提取出来 一个多维数组,其每一行对应于哈希中的一个数组。然后我走了第一排 将此矩阵放入另一个数组(@ arr1)并迭代通过它来查找是否有任何元素 在arr1中,它也在矩阵的其余行中。如果找到这样的元素,那就是 推到另一个包含所有元素的最终列表的数组。代码如下 (我希望它足够清楚):
sub construct_arr(my %records) {
my $len = keys %records;
my @matrix;
my $i = 0;
# Extract the values of the hash into a matrix
foreach my $key (keys %records) {
$matrix[$i] = $records{$key};
$i++;
}
my @arr1 = $matrix[0];
my @final;
# Iterate through each element of arr1
for my $j (0..$#{$arr1[0]}) {
my $count = 1;
# Iterate through each row of the matrix, starting from the second
for ( my $i = 1; $i < $len ; $i++ ) {
my $flag = 0;
# Iterate through each element of the row
for my $k (0..$#{$matrix[$i]}) {
if ($arr1[0][$j] eq $matrix[$i][$k]) {
$flag = 1;
$count++;
}
}
# On finding the first instance of the element in a row, go to the next row
if (!$flag == 1) {
last;
}
}
# If element is in all the rows, push it on to the final array
if ($count == $len) {
push(@final, $arr1[0][$j]);
}
}
return @final;
}
我知道上述工作,但我想知道是否有其他(perlish)方式来做到这一点。 我开始学习perl,我很有兴趣了解可以使我的工作更轻松的事情 在perl中与其他语言相比。如果我的代码是最好的,请告诉我 太。任何指导将不胜感激。谢谢!
答案 0 :(得分:6)
看一下Chris Charley's link来计算数组的交集。
哈希是解决这类问题的明确方法。与map
和grep
一起,解决方案可以简化为几行。
此程序使用sundar's数据来获取更好的内容,并且似乎可以满足您的需求。
use strict;
use warnings;
my %records = (
a => [ qw/ A B C / ],
b => [ qw/ C D E A / ],
c => [ qw/ A C E / ],
);
print "$_\n" for construct_arr(\%records);
sub construct_arr {
my $records = shift;
my %seen;
$seen{$_}++ for map @$_, values %$records;
grep $seen{$_} == keys %$records, keys %seen;
}
<强>输出强>
A
C
修改强>
我认为看到更多Perlish,整理自己的解决方案可能会有所帮助。
use strict;
use warnings;
my %records = (
a => [ qw/ A B C / ],
b => [ qw/ C D E A / ],
c => [ qw/ A C E / ],
);
print "$_\n" for construct_arr(\%records);
sub construct_arr {
my $records = shift;
my @matrix = values %$records;
my @final;
# iterate through each element the first row
for my $i ( 0 .. $#{$matrix[0]} ) {
my $count = 1;
# look for this value in all the rest of the rows, dropping
# out to the next row as soon as a match is found
ROW:
for my $j ( 1 .. $#matrix ) {
for my $k (0 .. $#{$matrix[$j]}) {
next unless $matrix[0][$i] eq $matrix[$j][$k];
$count++;
next ROW;
}
}
# If element is in all the rows, push it on to the final array
push @final, $matrix[0][$i] if $count == @matrix;
}
return @final;
}
输出与我自己的程序相同,但功能稍有不同,因为我假设每行中的值是唯一的。如果sama值出现不止一次,我的解决方案将会中断(同样适用于 sundar的)。如果可以接受,请告诉我。
答案 1 :(得分:3)
虽然海报解释说单个数组中没有重复内容,但这是我处理该情况的尝试(请注意稍微修改的测试数据 - 不应打印“5”):
#!/usr/bin/env perl
use warnings;
use strict;
my %records = (
a => [1, 2, 3],
b => [3, 4, 5, 1],
c => [1, 3, 5, 5]
);
my %seen;
while (my ($key, $vals) = each %records) {
$seen{$_}{$key} = 1 for @$vals;
}
print "$_\n" for grep { keys %{$seen{$_}} == keys %records } keys %seen;
答案 2 :(得分:1)
您可以使用scalar(keys %hash);
以下是满足您需求的示例代码:
#!/usr/bin/perl
use strict;
use warnings;
my %records = ( a => [1, 2, 3],
b => [3, 4, 5, 1],
c => [1, 3, 5]
);
my %count;
foreach my $arr_ref (values %records) {
foreach my $elem (@$arr_ref) {
$count{$elem}++;
}
}
my @intersection;
my $num_arrays = scalar(keys %records);
foreach my $elem (keys %count) {
#If all the arrays contained this element,
#allowing for multiple entries per array
if ($count{$elem} >= $num_arrays) {
push @intersection, $elem;
}
}
如果您需要在此代码中进行任何说明,请随时发表评论。构建@Intersection数组的第二个foreach是以这种方式编写的,只是为了清楚 - 如果你正在学习Perl,我建议你使用map
结构来研究和重写它,因为那可以说是更惯用的Perl。