在Perl中,是否有内置的方式来比较两个数组是否相等?

我有两个string数组,我想比较它们是否相等:

my @array1 = ("part1", "part2", "part3", "part4"); my @array2 = ("part1", "PART2", "part3", "part4"); 

有一种内置的方法来比较数组,比如标量吗? 我试过了:

 if (@array1 == @array2) {...} 

但它只是在标量上下文中评估每个数组,因此比较每个数组的长度。

我可以推出我自己的function来做,但似乎是这样一个低级别的操作,应该有一个内置的方式来做到这一点。 在那儿?

编辑:可悲的是,我没有访问5.10 +或可选组件。

有一个新的智能匹配算子 :

 #!/usr/bin/perl use 5.010; use strict; use warnings; my @x = (1, 2, 3); my @y = qw(1 2 3); say "[@x] and [@y] match" if @x ~~ @y; 

关于Array :: Compare :

在内部,比较器通过使用连接将两个数组转换为string并使用eq比较string来比较两个数组。

我想这是一个有效的方法,但只要我们使用string比较,我宁愿使用像这样的东西:

 #!/usr/bin/perl use strict; use warnings; use List::AllUtils qw( each_arrayref ); my @x = qw(1 2 3); my @y = (1, 2, 3); print "[@x] and [@y] match\n" if elementwise_eq( \(@x, @y) ); sub elementwise_eq { my ($xref, $yref) = @_; return unless @$xref == @$yref; my $it = each_arrayref($xref, $yref); while ( my ($x, $y) = $it->() ) { return unless $x eq $y; } return 1; } 

如果你正在比较的数组很大,join它们将会做很多工作,并且消耗大量的内存,而不是仅仅比较每个元素。

更新:当然,应该testing这样的陈述。 简单的基准:

 #!/usr/bin/perl use strict; use warnings; use Array::Compare; use Benchmark qw( cmpthese ); use List::AllUtils qw( each_arrayref ); my @x = 1 .. 1_000; my @y = map { "$_" } 1 .. 1_000; my $comp = Array::Compare->new; cmpthese -5, { iterator => sub { my $r = elementwise_eq(\(@x, @y)) }, array_comp => sub { my $r = $comp->compare(\(@x, @y)) }, }; 

这是最坏的情况,其中elementwise_eq必须遍历两个数组中的每个元素1_000次,并显示:

             评价迭代器array_comp
迭代器246 / s  -  -75%
 array_comp 1002 / s 308% - 

另一方面,最好的情况是:

 my @x = map { rand } 1 .. 1_000; my @y = map { rand } 1 .. 1_000; 
              评价array_comp iterator
 array_comp 919 / s  -  -98%
迭代器52600 / s 5622% - 

iterator性能下降相当快,但是:

 my @x = 1 .. 20, map { rand } 1 .. 1_000; my @y = 1 .. 20, map { rand } 1 .. 1_000; 
              评价迭代器array_comp
迭代器10014 / s  -  -23%
 array_comp 13071 / s 31% - 

我没有看内存利用率。

还有Test :: More的is_deeply()函数,它也会显示结构不同的地方,或者Test :: Deep的eq_deeply(),它不需要testing工具(只返回true或false)。

不是内置的,但有Array :: Compare 。

这是Perl核心所没有的操作之一,我认为这些操作是由于教学原因 – 也就是说,如果你正在尝试这样做,可能会出现错误。 这个最具说明性的例子,我认为是没有核心read_entire_file函数; 基本上,在核心中提供这个function会让人们认为这样做是一个好主意 ,相反,Perl的devise方式是轻轻地推动你逐行处理文件,这通常要远远多于有效的,否则一个更好的主意,但新手程序员很less感到舒服,他们需要一些鼓励去那里。

这同样适用于这里:通过比较两个数组,可能有更好的方法来做出你想要完成的决定。 不一定 ,但可能。 所以Perl推动着你去思考完成你的目标的其他方式。

Perl 5.10为您提供了智能匹配运算符。

 use 5.010; if( @array1 ~~ @array2 ) { say "The arrays are the same"; } 

否则,正如你所说,你会有自己的顶级滚动。

只要你使用的是perl 5.10或更新版本,你可以使用智能匹配运算符 。

 if (@array1 ~~ @array2) {...} 

更简单的解决scheme更快:

 #!/usr/bin/perl use strict; use warnings; use Array::Compare; use Benchmark qw( cmpthese ); use List::AllUtils qw( each_arrayref ); my @x = 1 .. 1_000; my @y = map { "$_" } 1 .. 1_000; my $comp = Array::Compare->new; cmpthese -2, { iterator => sub { my $r = elementwise_eq(\(@x, @y)) }, my_comp => sub { my $r = my_comp(\(@x, @y)) }, array_comp => sub { my $r = $comp->compare(\(@x, @y)) }, }; @x = 1 .. 20, map { rand } 1 .. 1_000; @y = 1 .. 20, map { rand } 1 .. 1_000; cmpthese -2, { iterator => sub { my $r = elementwise_eq(\(@x, @y)) }, my_comp => sub { my $r = my_comp(\(@x, @y)) }, array_comp => sub { my $r = $comp->compare(\(@x, @y)) }, }; sub elementwise_eq { my ($xref, $yref) = @_; return unless @$xref == @$yref; my $it = each_arrayref($xref, $yref); while ( my ($x, $y) = $it->() ) { return unless $x eq $y; } return 1; } sub my_comp { my ($xref, $yref) = @_; return unless @$xref == @$yref; my $i; for my $e (@$xref) { return unless $e eq $yref->[$i++]; } return 1; } 

并导致perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi

  Rate iterator array_comp my_comp iterator 1544/s -- -67% -80% array_comp 4697/s 204% -- -41% my_comp 7914/s 413% 68% -- Rate iterator array_comp my_comp iterator 63846/s -- -1% -75% array_comp 64246/s 1% -- -75% my_comp 252629/s 296% 293% -- 

如果套pipe是唯一的区别,你可以简单地使用:

 if (lc "@array1" eq lc "@array2") {...} 

"@array1"返回与join ( " ", @array1 )

这个问题已经变成了一个非常有用的资源。 ++为基准和讨论。

正如其他人指出,智能匹配function存在问题,正在逐步淘汰。 还有一些“不太聪明”的select(因此避免了这些问题),并且规模小,速度相当快,并且没有太多的非CORE依赖关系。

  • Smart::Match
  • match::simple (和match::smart
  • Scalar::In

你可以通过@brian d foy查看一些博客文章 ,以及2011年和2012年 @ rjbs上的p5p邮件存档线索,find关于未来历史的一些相当好的讨论的链接。

比较数组可以简单而有趣!

 use v5.20; use match::simple; my @x = (1, 2, 3); my @y = qw(1 2 3); say "[@x] and [@y] match" if @x |M| @y; __END__ [1 2 3] and [1 2 3] match 

如果数组很简单,特别有趣。 但是一个数组可能是一个复杂的事情,有时候你需要从比较结果中得到不同的信息。 为此, Array :: Compare可以使调整的比较更容易。

如果顺序和重复值不重要,只是值相等(即设置比较),您可以使用Set::Scalar

它重载了常见的操作符,如==!=

 my @array1 = ("part1", "part2", "part3", "part4"); my @array2 = ("part1", "PART2", "part3", "part4"); if ( Set::Scalar->new(@array1) == Set::Scalar->new(@array2) ) {...} 

另外,还有Algorithm::DiffList::Compare

为了检查两个数组的相等性,试试这个。 在给定的代码中,如果%eq_or_not有任何值,那么两个数组不相等,否则它们是相等的。

 my @array1 = ("part1", "part2", "part3", "part4"); my @array2 = ("part1", "PART2", "part3", "part4"); my %eq_or_not; @eq_or_not{ @array1 } = undef; delete @eq_or_not{ @array2 }; 

可以在标量上下文中使用grep函数( http://perldoc.perl.org/functions/grep.html#grep-BLOCK-LIST

(0 eq(grep {$ array1 [$ _] ne $ array2 [$ _]} 0 .. $#array1))if $#array1 eq $#array2;

HIH。

如果唯一的标准是“它们是不是等价的”,而不是更复杂的问题,“它们是否等价,如果它们不同,怎么办? 有更快/更丑陋的方法来做到这一点。 例如,将每个数组的整体粉碎成两个标量并进行比较。

例如

 my @array1 = ("part1", "part2", "part3", "part4"); my @array2 = ("part1", "PART2", "part3", "part4"); my $smash1 = join("", @array1); my $smash2 = join("", @array2); if ($smash1 eq $smash2) { # equal } else { #unequal } 

是的,我可能只是让拉里·沃尔哭了。