したがって、必要なのは、2 つの配列が perl で同一かどうかを判断する簡単な方法だけです。順序は関係ないので、次のようなものを探しています。
my @a = (1, 2, 3);
my @b = (2, 3, 1);
my @c = (1, 2, 4);
&identical(@a, @b)
1 を返します
&identical(@a, @c)
0 を返します
ありがとう!
要素の数をハッシュで集計できます。(要素 => カウント) ハッシュを作成し、最初の配列にその要素が含まれるたびにカウントを増やし、もう一方の配列に含まれるたびにカウントを減らします (またはその逆)。2 つの配列の要素がすべて同じ場合、ハッシュのすべての値は 0 になります。
sub have_same_elements {
my ($arr1, $arr2) = @_;
my %counts = ();
$counts{$_} += 1 foreach (@$arr1);
$counts{$_} -= 1 foreach (@$arr2);
return !(grep { $_ != 0 } values %counts);
}
$a_and_b_same = have_same_elements(\@a, \@b); # will be true
$a_and_c_same = have_same_elements(\@a, \@c); # will be false
(これは、独自の文字列化を行うオブジェクトでは機能する場合と機能しない場合があります。ハッシュ キーは参照になることはできないため、Perl は参照を使用するときに参照を文字列化します。デフォルトの文字列化子は、参照を のようなものに変換しますARRAY(0x12345678)
。ただし、オブジェクトが独自の文字列化を行い、異なる参照に対して異なる文字列を返さない場合、これはおそらく壊れます。
Perl 5.10
以上を使用している場合(そうでない場合は、実際にアップグレードする必要があります)、スマートマッチ演算子を使用できます。
use strict;
use warnings;
my @a = (1, 2, 3);
my @b = (2, 3, 1);
my @c = (1, 2, 4);
#sort each of them (numerically)
@a = sort { $a <=> $b } @a;
@b = sort { $a <=> $b } @b;
@c = sort { $a <=> $b } @c;
if ( @a ~~ @b ) {
print "\@a and \@b are the same! (after sorting)\n";
}
else {
print "nope\n";
}
if ( @a ~~ @c ) {
print "\@a and \@c are the same! (after sorting)\n";
}
else {
print "nope\n";
}
独自の関数をロールすることもできます。
use strict;
use warnings;
my @a = (1, 2, 3);
my @b = (2, 3, 1);
my @c = (1, 2, 4);
print same_elements(\@a, \@b) . "\n";
print same_elements(\@a, \@c) . "\n";
#arguments are two array references
sub same_elements {
my $array_ref_1 = shift;
my $array_ref_2 = shift;
my @arr1 = @$array_ref_1;
my @arr2 = @$array_ref_2;
#If they are not the same length, we are done.
if( scalar(@arr1) != scalar(@arr2) ) {
return 0;
}
#sort them!
@arr1 = sort { $a <=> $b } @arr1;
@arr2 = sort { $a <=> $b } @arr2;
foreach my $i( 0 .. $#arr1 ) {
if ( $arr1[$i] != $arr2[$i] ) {
return 0;
}
}
return 1;
}
まず、機能を再考する必要があります。
identical(@a, @b);
関数に 2 つの配列を渡すのではなく、両方の配列のすべての要素を含む 1 つの配列を渡します。まるであなたが言ったかのようです:
identical(1, 2, 3, 2, 3, 1);
関数を機能させるには、配列への参照を渡す必要があります。
identical(\@a, \@b);
サブルーチンのプロトタイプを作成することをお勧めしますが、おそらくそれによって解決される問題がさらに発生するでしょう。
順序が重要でない場合は、比較する前に配列を並べ替えます。騙すこともできるかもしれません...
sub identical {
my $array_ref_1 = shift;
my $array_fef_2 = shift;
use Digest::SHA qw(sha1_hex);
if ( ref( $array_ref_1 ) ne "ARRAY") or ( ref( $array_ref_2 ) ne "ARRAY") {
return; #Error, need two array references
}
# Dereference Arrays
my @array_1 = @{$array_ref_1};
my @array_2 = @{$array_ref_2};
# Setup Arrays to be one big scalar
my $scalar_1 = join "\n", sort @array_1;
my $scalar_2 = join "\n", sort @array_2;
my $checksum_1 = sha1_hex $scalar_1;
my $checksum_2 = sha1_hex $scalar_2;
if ($checksum_1 eq $checksum_2) {
return 1;
}
else {
return 0_but_true;
いくつかのメモ:
0_but_true
0 を返しますが、同時に真の値を返します。if ( identical( \@A, \@B ) ) {
このようにして、関数が機能していることを確認するようなことができます。次に、ゼロか 1 かをテストできます。本当の問題は、次のような複数行の配列がある場合です。
@a = ("this", "that", "the\nother");
@b = ("this", "that\nthe", "other");
私が行った方法を使用するjoin
と、結果のスカラーが等しくなります。