プロが教えるわが家の防犯対策術!

スカラ型なら
my $a = "a";
my $b = "b";

if( $a eq $b)の用に比較が簡単に出来ますが、
配列やハッシュはどのように中身が同じかどうか調べることは可能でしょうか?

配列でも複雑な(例えば配列のデータがハッシュ値)のような以下の
ものを中身が同じが比較する方法です。
固定でなく、どんなデータが入ってきても数やキーが異なっても比較する方法が知りたいです。


my @ary1 = ();
$ary[0]{'test_a'} = "a";
$ary[0]{'test_b'} = "b";
$ary[1]{'test_a'} = "aa";
$ary[1]{'test_b'} = "bb";

my @ary2 = ();
$ary[0]{'test_a'} = "aa";
$ary[0]{'test_b'} = "bb";
$ary[1]{'test_a'} = "aaa";
$ary[1]{'test_b'} = "bbb";

A 回答 (6件)

Test::Deepのeq_deeply()が簡単で使いやすいです。


ハッシュでも、配列でも何でも比較できるみたいです。例題であれば↓

use Test::Deep;

my @ary1 = ();
$ary1[0]{'test_a'} = "a";
$ary1[0]{'test_b'} = "b";
$ary1[1]{'test_a'} = "aa";
$ary1[1]{'test_b'} = "bb";

my @ary2 = ();
$ary2[0]{'test_a'} = "aa";
$ary2[0]{'test_b'} = "bb";
$ary2[1]{'test_a'} = "aaa";
$ary2[1]{'test_b'} = "bbb";

if(eq_deeply( \@ary1, \@ary2, 'Compare array' )){
print "Same structure\n";
}else{
print "Different structure\n";
}
    • good
    • 0

とりあえず,「中身を見る」のが先決だと思うので,


Data::Dumper を使うというのはどうでしょうか.
Dumperで文字列にして
それを「文字列として」比較しています.
Test系のモジュールに
この手の比較に特化したものがあるかもしれませんね

use strict;
use warnings;

use Data::Dumper;

my @ary1 = (
{'test_b' => "b"},
{'test_a' => "aa"},
{'test_b' => "bb"},
);

my @ary2 = (
{'test_b' => "c"},
{'test_a' => "aa"},
{'test_b' => "bb"},
);


if (Dumper(@ary1) eq Dumper(@ary2)){
print "EQ";
}else{
print "NOT EQ";
}
    • good
    • 0

あ, 言い忘れてた. 「中身が複雑」だとすると, 「同じ」かどうかの判定から考えないとダメですね.


例えば,
$a = [ 1 ];
$b = [ 1 ];
としたときに, $a と $b は「別のリファレンス」だけど「同じデータを持つ配列」のリファレンスではあるわけで, このときに「同じ」とするか「違う」とするかという問題があります.
もっとも, 「中身が複雑」で「簡単にチェック」は矛盾してるような気がするなぁ....
    • good
    • 0

ん~, それぞれのデータ型に応じて適切に比較するサブルーチンを作り, 再帰的にチェックするしかないんじゃないかなぁ?


例えば, 配列だと
sub check_array($$) {
my ($array1, $array2) = @_;
return 0 if $#$array1 != $#$array2;
for my $i (0 .. $#$array1) {
my $type1 = ref $array1->[$i];
my $type2 = ref $array2->[$i];
return 0 if $type1 ne $type2;
return 0 if ! $check{$type1}->($array1->[$i], $array2->[$i]);
}
1;
}
みたいな. あ, %check は
%check = (
SCALAR => \&check_scalar,
ARRAY => \&check_array,
...);
みたいにデータ型に対して比較ルーチンを記憶しておくハッシュです.
    • good
    • 0

単純にループを積み重ねただけです。



foreach my $index_1 (0 .. $#ary1) {
foreach my $key_1 (keys %{$ary1[$index_1]}) {
foreach my $index_2 (0 .. $#ary2) {
foreach my $key_2 (keys %{$ary2[$index_2]}) {
if ($ary1[$index_1]->{$key_1} eq $ary2[$index_2]->{$key_2}) { ... } # 値のみ同じ
# if ($key_1 eq $key_2 && $ary1[$index_1]->{$key_1} eq $ary2[$index_2]->{$key_2}) { ... } # キーと値が同じ
}
}
}
}
    • good
    • 0

@ary1と@ary2の比較ならそれなりの処理が必要です


>固定でなくどんなデータが入ってきても数やキーが異なっても比較する方法
例えにある配列を比較するならこんな感じでしょうか・・・
※素人なのでスマートでカッコイイのは書けませんm(_ _;m

my @ary1 = ();
$ary1[0]{'test_a'} = "a";
$ary1[0]{'test_b'} = "b";
$ary1[1]{'test_a'} = "aa";
$ary1[1]{'test_b'} = "bb";

my @ary2 = ();
$ary2[0]{'test_a'} = "a";
$ary2[0]{'test_b'} = "bb";
$ary2[1]{'test_a'} = "aaa";
$ary2[1]{'test_b'} = "bbb";

if($#ary1 != $#ary2){
print "配列の数が異なる\n";
}else{
for($i=0;$i<=$#ary1;$i++){
if(join(",",sort keys(%{$ary1[$i]})) ne join(",",sort keys(%{$ary2[$i]}))){
print "\$ary1[$i]と\$ary2[$i]には異なるキーが存在\n";
}else{
foreach $key (sort keys(%{$ary1[$i]})){
if($ary1[$i]{$key} ne $ary2[$i]{$key}){
print "\$ary1[$i]{'$key'}と\$ary2[$i]{'$key'}は不一致\n";
}else{
print "\$ary1[$i]{'$key'}と\$ary2[$i]{'$key'}は一致\n";
}
}
}
}
}
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!