簡體   English   中英

在Perl中,是否有內置的方法來比較兩個數組的相等性?

[英]In Perl, is there a built in way to compare two arrays for equality?

我有兩個字符串數組,我想比較相等:

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

是否有內置的方法來比較數組,就像標量一樣? 我試過了:

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

但它只是在標量上下文中評估每個數組,因此比較了每個數組的長度。

我可以使用自己的函數來完成它,但它看起來像是一個低級操作,應該有一個內置的方法來做它。 在那兒?

編輯:遺憾的是,我無法訪問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

在內部,比較器通過使用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;
}

如果您要比較的數組很大,那么加入它們將會做很多工作並消耗大量內存,而不是逐個比較每個元素。

更新:當然,應該測試這樣的陳述。 簡單的基准:

#!/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次,並顯示:

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;
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;
Rate   iterator array_comp
iterator   10014/s         --       -23%
array_comp 13071/s        31%         --

我沒有看內存利用率。

還有Test :: More的is_deeply()函數,它也會精確顯示結構的不同之處,或者Test :: Deep的eq_deeply(),它不需要測試工具(只返回true或false)。

不是內置的,但有Array :: Compare

這是Perl核心遺漏的操作之一,因為我認為這是教學的原因 - 也就是說,如果你試圖這樣做,可能會出現問題。 我認為,最具說明性的例子是缺少核心read_entire_file函數; 基本上,在核心中提供該功能會讓人們認為這樣做是個好主意 ,相反,Perl的設計方式會輕輕地推動您逐行處理文件,這通常會更多有效率和其他更好的想法,但新手程序員很少習慣它,他們需要一些鼓勵去實現。

這同樣適用於:通過比較兩個數組,可能有更好的方法來確定你想要完成的決定。 不一定 ,但可能。 所以Perl正在推動你思考實現目標的其他方法。

Perl 5.10為您提供智能匹配運算符。

use 5.010;

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

否則,正如你所說,你將有自己的頂級。

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

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

更簡單的解決方案更快:

#!/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%         --

這個問題已經變成了一個非常有用的資源。 ++用於基准和討論。

正如其他人所指出的,智能匹配功能存在問題,並且正在逐步淘汰其目前的形式。 有些替代方案“不太聰明”(因此避免了這些問題),而且體積小,速度相當快,並且沒有太多的非CORE依賴項。

你可以找到更多有關未來的歷史一些非常好的討論~~看在一對夫婦的博客文章由@布賴恩d FOY和P5P郵件歸檔線程從2011年2012從@rjbs。

比較數組可以簡單而有趣!

use v5.20;   
use match::smart; 
my @x = (1, 2, 3);       
my @y = qw(4 5 6);    
my @z = qw(4 5 6);   
say \@x |M| \@y ? "[\@x] and [\@y] match": "no match";  
say \@y |M| \@z ? "[\@y] and [\@z] match": "no match";

__END__                              
@y and @z match, @x and @y do not

...如果陣列很簡單,特別有趣。 但是數組可能是一個復雜的事情,有時您需要比較結果中的不同類型的信息。 為此, Array :: Compare可以更輕松地進行微調比較。

如果套管是唯一的區別,你可以簡單地使用:

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

"@array1"返回與join ( " ", @array1 )相同join ( " ", @array1 )

如果順序和重復值無關緊要但只有值相等(即設置比較),則可以使用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 };

Data::Cmp是另一個最近的選擇。 cmp_data()函數的操作類似於cmp操作符(有關cmp用法,請參閱perlop )。

例:

use 5.10;
use Data::Cmp qw/cmp_data/;

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

# sample usage 
say "1 & 2 are different" if cmp_data(\@array1, \@array2) ;
sat "2 & 3 are the same" unless cmp_data(\@array2, \@array3) ;

也可以比較哈希和更復雜的嵌套數據結構(在合理范圍內)。 對於沒有非核心依賴關系的單個模塊, Data::Cmp非常“聰明” ;-) ... errm我的意思是“有用”。

可以在標量上下文中使用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
}

是的,我可能只是讓Larry Wall哭了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM