55

等しいかどうかを比較したい文字列の配列が 2 つあります。

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

スカラーのように配列を比較する組み込みの方法はありますか? 私は試した:

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

しかし、スカラーコンテキストで各配列を評価しただけなので、各配列の長さを比較しました。

私はそれを行うために独自の関数をロールすることができますが、それを行うための組み込みの方法が必要なほど低レベルの操作のようです。ある?

編集: 残念ながら、私は 5.10+ またはオプションのコンポーネントにアクセスできません。

4

15 に答える 15

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;

Array::Compareについて:

内部的には、コンパレータは join を使用して両方の配列を文字列に変換し、 を使用して文字列を比較することにより、2 つの配列を比較します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;
}

比較している配列が大きい場合、それらを結合すると、各要素を 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 回実行する必要がある最悪のシナリオであり、次のようになります。

             レート イテレータ array_comp
イテレータ 246/秒 -- -75%
array_comp 1002/s 308% --

一方、最良のシナリオは次のとおりです。

my @x = map { rand } 1 .. 1_000;
my @y = map { rand } 1 .. 1_000;
              レート array_comp イテレータ
array_comp 919/s -- -98%
イテレータ 52600/秒 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/秒 31% --

メモリ使用率は見ていません。

于 2009-10-22T19:46:09.917 に答える
14

組み込みではありませんが、Array::Compareがあります。

これは、教訓的な理由で Perl コアから取り残されている操作の 1 つです。つまり、それを行おうとすると、おそらく何か問題があるということです。これの最もわかりやすい例は、コアread_entire_file機能の欠如だと思います。基本的に、コアでその機能を提供すると、人々はそれを行うのが良い考えであると考えるようになりますが、代わりに、Perl はファイルを一度に 1 行ずつ処理するようにやさしく後押しするように設計されています。効率的で、そうでなければより良いアイデアですが、初心者のプログラマーがそれに慣れることはめったになく、そこにたどり着くにはいくらかの励ましが必要です.

ここでも同じことが当てはまります。2 つの配列を比較することで、達成しようとしている決定を行うためのより良い方法がおそらくあるでしょう。必ずしもそうではありません、おそらく。そのため、Perl は、目標を達成するための他の方法を考えるように促しています。

于 2009-10-22T19:35:31.560 に答える
9

Perl 5.10 では、スマート マッチ演算子が提供されます。

use 5.010;

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

そうでなければ、あなたが言ったように、あなたはあなた自身のトップロールを持っているでしょう.

于 2009-10-22T19:45:24.990 に答える
8

perl 5.10 以降を使用している限り、スマート マッチ演算子を使用できます。

if (@array1 ~~ @array2) {...}
于 2009-10-22T19:44:06.813 に答える
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;
}

結果は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%         --
于 2011-12-01T01:48:36.303 に答える
1

大文字と小文字が唯一の違いである場合は、次を使用できます。

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

"@array1"と同じものを返しますが、join ( " ", @array1 )

于 2009-11-25T18:58:18.010 に答える
1

2 つの配列の等価性をチェックするには、これを試してください。指定されたコードで、%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 };
于 2017-03-01T10:33:11.350 に答える
-2

唯一の基準が「同等かどうか」であり、「同等かどうか、また異なる場合はどのように異なるか」というより複雑な質問ではない場合。それを行うには、はるかに迅速で醜い方法があります。たとえば、各配列全体を 2 つのスカラーに分割し、それらを比較します。

例えば

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
}

はい、おそらくラリー・ウォールを泣かせただけです。

于 2011-11-30T22:51:43.307 に答える