Perl 如何计算可能包含重复元素的两个数组之间的交集?
如何计算两个数组的交集(公共元素)?我尝试使用以下代码:Perl 如何计算可能包含重复元素的两个数组之间的交集?,perl,Perl,如何计算两个数组的交集(公共元素)?我尝试使用以下代码: my @array1 = (1, 2, 3, 3, 3, 3, 4); my @array2 = (2, 3, 4, 4, 4); my %original = (); my @isect = (); map { $original{$_} = 1 } @array1; @isect = grep { $original{$_} } @array2; print "@isect\n"; 结果是2 3 4 4,但我想得到2 3 4 另
my @array1 = (1, 2, 3, 3, 3, 3, 4);
my @array2 = (2, 3, 4, 4, 4);
my %original = ();
my @isect = ();
map { $original{$_} = 1 } @array1;
@isect = grep { $original{$_} } @array2;
print "@isect\n";
结果是2 3 4 4
,但我想得到2 3 4
另一个例子:
@array1 = (5, 6, 7, 7, 7, 1, 4);
@array2 = (5, 6, 7, 6, 7, 7, 4, 4, 4);
这应该返回
56774
,而不是5676774
。如何实现这一点?在第一个示例中,您已经消除了所需输出中的重复元素。在你的第二个例子中,你还没有——我甚至不明白你想要的结果(因此,我将解决您所说的第一个示例输出所需的问题
更改:
@isect = grep { $original{$_} } @array2;
致:
@isect=grep{exists$original{$}和$original{$}++<2}@array2;
产生:
2 3 4第一个例子
及
第二个例子是5 6 7 4
测试代码:
my @array1 = (1, 2, 3,3,3,3,4);
my @array2 = (2, 3, 4,4,4);
print intersect( \@array1, \@array2);
@array1 = (5,6,7,7,7,1,4);
@array2 = (5,6,7,6,7,7,4,4,4);
print intersect( \@array1, \@array2);
sub intersect {
my ($first, $second) = @_;
my @array1 = @{ $first };
my @array2 = @{ $second };
my %original = ();
my @isect = ();
map { $original{$_} = 1 } @array1;
@isect = grep { exists $original{$_} and $original{$_}++ < 2 } @array2;
return "@isect\n";
}
my@array1=(1,2,3,3,3,4);
my@array2=(2,3,4,4,4);
打印相交(\@array1,\@array2);
@数组1=(5,6,7,7,1,4);
@数组2=(5,6,7,6,7,7,4,4,4);
打印相交(\@array1,\@array2);
子相交{
我的($first,$second)=@;
my@array1=@{$first};
my@array2=@{$second};
我的%original=();
我的@isect=();
map{$original{$}=1}@array1;
@isect=grep{exists$original{$}和$original{$}++<2}@array2;
返回“@isect\n”;
}
perldoc perlfaq4
有答案
这是它提供的多用途代码
my (@union, @intersection, @difference);
my %count = ();
foreach my $element (@array1, @array2) {
$count{$element}++
}
foreach my $element (keys %count) {
push @union, $element;
push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;
}
在第二个示例中,每个数组中有三个7,因此他们希望结果也包含三个7。您不应该不必要地复制这些数组,不应该将空列表分配给已经为空的变量,第一个
映射应该是for
循环的,以及输出格式(“@isect\n”
)应该在sub之外完成。这将给出my%original;$original{$}=1 for@$first;返回grep{exists$original{$}和$original{$}++<2}@$second;
,最好写为my%original=map{$}$}@$first;返回grep{delete($original{$}})@$second;
。但是像这件衣服一样,我没有提到,这不是OP需要的。ikegami:我试着让我的日常工作看起来尽可能像最初的一样。但是因为我没有真正理解这个问题,我不应该麻烦。很抱歉浪费带宽。map
是“映射”的意思你的语句map{$original{$}=1}@array1
通过创建一个新的列表然后丢弃它来滥用它。正确的方法是$original{$}=1 for@array1
或my%original=map{$}@array1
。
my @array1 = ( 5, 6, 7, 7, 7, 1, 4 );
my @array2 = ( 5, 6, 7, 6, 7, 7, 4, 4, 4 );
my %counts;
++$counts{$_} for @array1;
my @common = grep { --$counts{$_} >= 0 } @array2;
say "@common"; # 5 6 7 7 7 4
my (@union, @intersection, @difference);
my %count = ();
foreach my $element (@array1, @array2) {
$count{$element}++
}
foreach my $element (keys %count) {
push @union, $element;
push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;
}