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

Bil*_*ill 51 arrays perl compare match

我有两个字符串数组,我想比较相等:

my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");
Run Code Online (Sandbox Code Playgroud)

是否有内置的方法来比较数组,就像标量一样?我试过了:

if (@array1 == @array2) {...}
Run Code Online (Sandbox Code Playgroud)

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

我可以使用自己的函数来完成它,但它看起来像是一个低级操作,应该有一个内置的方法来做它.在那儿?

编辑:遗憾的是,我无法访问5.10+或可选组件.

Sin*_*nür 56

有一个新的智能匹配运营商:

#!/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;
Run Code Online (Sandbox Code Playgroud)

关于Array :: Compare:

在内部,比较器通过使用join将两个数组转换为字符串并使用比较字符串来比较两个数组eq.

我想这是一个有效的方法,但只要我们使用字符串比较,我宁愿使用类似的东西:

#!/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;
}
Run Code Online (Sandbox Code Playgroud)

如果您要比较的数组很大,那么加入它们将会做很多工作并消耗大量内存,而不是逐个比较每个元素.

更新:当然,应该测试这样的陈述.简单的基准:

#!/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)) },
};
Run Code Online (Sandbox Code Playgroud)

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

             Rate   iterator array_comp
iterator    246/s         --       -75%
array_comp 1002/s       308%         --

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

my @x = map { rand } 1 .. 1_000;
my @y = map { rand } 1 .. 1_000;
Run Code Online (Sandbox Code Playgroud)
              Rate array_comp   iterator
array_comp   919/s         --       -98%
iterator   52600/s      5622%         --

iterator 然而,性能下降很快:

my @x = 1 .. 20, map { rand } 1 .. 1_000;
my @y = 1 .. 20, map { rand } 1 .. 1_000;
Run Code Online (Sandbox Code Playgroud)
              Rate   iterator array_comp
iterator   10014/s         --       -23%
array_comp 13071/s        31%         --

我没有看内存利用率.

  • 2013年5月发布的Perl版本5.18中不推荐使用Smart运算符. (11认同)
  • @Bill 谢谢,但分析不是那么彻底。它最起码教我不要在没有测量的情况下做出假设,并且在大多数情况下,你可以做得比“Array::Compare”更糟糕。 (2认同)
  • 简单的`my $i;for my $e (@$xref) {return until $e eq $yref->[$i++];}` 快得多(v5.14.2)。 (2认同)

Eth*_*her 22

还有Test :: More的is_deeply()函数,它也会精确显示结构的不同之处,或者Test :: Deep的eq_deeply(),它不需要测试工具(只返回true或false).

  • 除非在测试中,否则您不得“使用”用于测试的模块。 (2认同)

cha*_*aos 14

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

这是Perl核心遗漏的操作之一,因为我认为这是教学的原因 - 也就是说,如果你试图这样做,可能会出现问题.我认为,最具说明性的例子是没有核心read_entire_file功能; 基本上,在核心中提供该功能会让人们认为这样做是个好主意,但是,Perl的设计方式可以轻轻地推动您逐行处理文件,这通常会更多有效率和其他更好的想法,但新手程序员很少习惯它,他们需要一些鼓励去实现.

这同样适用于:通过比较两个数组,可能有更好的方法来确定你想要完成的决定.不是必然,但可能.所以Perl正在推动你思考实现目标的其他方法.

  • 作为一种富有表现力的语言,Perl可以很好地让你思考你在做什么. (2认同)

Dav*_*ris 9

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

use 5.010;

if( @array1 ~~ @array2 )
{
    say "The arrays are the same";
}
Run Code Online (Sandbox Code Playgroud)

否则,正如你所说,你将有自己的顶级.

  • 我真的不喜欢使用术语"可比较"来描述阵列上智能匹配的行为.我自动将其视为"能够被比较"(这将是相当无用的行为)而不是"等同"(这将是一个更好的术语,恕我直言). (6认同)
  • 实际上,这不会告诉你阵列是否相同,但它们是否具有可比性*. (3认同)
  • 更糟糕的是,这取决于您使用的是5.10.0还是5.10.1+.在5.10.0确实检查数组是否相等. (2认同)
  • 智能运算符在 2013 年 5 月发布的 Perl 5.18 版中已弃用。 (2认同)

Que*_*tin 8

只要您使用perl 5.10或更高版本,就可以使用智能匹配运算符.

if (@array1 ~~ @array2) {...}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这不会告诉你阵列是否相同,但它们是否具有可比性*. (4认同)
  • 智能运算符在 2013 年 5 月发布的 Perl 5.18 版中已弃用。 (2认同)

Hyn*_*dil 6

更简单的解决方案更快:

#!/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;
}
Run Code Online (Sandbox Code Playgroud)

并导致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%         --
Run Code Online (Sandbox Code Playgroud)