2016-05-10 20 views
2

これは私のシナリオです.2つのJSONファイルからデコードされたハッシュが2つあります。Perl - 2つのネストされたハッシュを比較します。

私は2複雑なハッシュを持って、

$hash1 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v1, v2, v3] }} 
$hash2 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v3, v2, v1] }} 

私は平等のためにこれらの2ハッシュを比較したい、とのデータ比較に使用::比較して、テストのis_deeply ::詳しいです。どちらも配列の順序を無視しません。
キー 'k21'の配列値の順序を無視して比較したいと思います。
My Appは配列を 'keys%hash'からランダムに並べ替えます。
Data :: Compareの 'ignore_hash_keys'を試しましたが、ハッシュが複雑になることがあり、無視したくない場合があります。

キー 'k21'はハッシュの配列を持つこともあります。

$hash3 = {k1=> { k11 => v1}, k2 => { k21 => [{v3 => v31}, {v2 => v22}] }} 

どのように配列の順序を無視することによって、このような複雑なハッシュを比較しますか。

答えて

5

は、cmp_deeplyです。 Test :: Moreのis_deeplyよりも多用途です。

use Test::Deep; 

my $hash1 = { 
    k1 => { k11 => 'v1', k12 => 'v2' }, k2 => { k21 => [ 'v1', 'v2', 'v3' ] } }; 
my $hash2 = { 
    k1 => { k11 => 'v1', k12 => 'v2' }, k2 => { k21 => bag('v3', 'v2', 'v1') } }; 

cmp_deeply($hash1, $hash2,); 

トリックはbag() functionであり、要素の順序は無視されます。

これは、つまり、それはバッグ比較二つの配列を比較するが、要素の順序を無視しない[...]


更新

your commentから

ハッシュ内のすべての配列参照を動的に取り除くにはどうすればいいですか?

Test :: Deepのコードをいくつか調べて、上書きすることができることを示しました。私はat Test::Deep自身を最初に見て、配列を扱うTest::Deep::Arrayがあることを発見しました。 T :: Dの中のものを扱うパッケージはすべてa descend methodです。そのため、ここにフックする必要があります。

Sub::Overrideは、タイプグロブを使用するのではなく、一時的にアイテムをオーバーライドするのに最適です。

基本的には、電話番号bag()にの電話番号をTest::Deep::Array::descendの最終行に置き換えてください。残りは単純にコピーされます(インデントは私のものです)。 monkey-patchingの場合、わずかな変更を加えた既存のコードのコピーが通常は最も簡単な方法です。

use Test::Deep; 
use Test::Deep::Array; 
use Sub::Override; 

my $sub = Sub::Override->new(
    'Test::Deep::Array::descend' => sub { 
     my $self = shift; 
     my $got = shift; 

     my $exp = $self->{val}; 

     return 0 unless Test::Deep::descend( 
      $got, Test::Deep::arraylength(scalar @$exp)); 

     return 0 unless $self->test_class($got); 

     return Test::Deep::descend($got, Test::Deep::bag(@$exp)); 
    } 
); 

my $hash1 = { 
    k1 => { k11 => 'v1', k12 => 'v2' }, 
    k2 => { k21 => [ 'v1', 'v2', 'v3' ] } 
}; 
my $hash2 = { 
    k1 => { k11 => 'v1', k12 => 'v2' }, 
    k2 => { k21 => [ 'v3', 'v2', 'v1' ] } 
}; 

cmp_deeply($hash1, $hash2); 

これでテストに合格します。

$subを未定義または有効範囲外に出すことでオーバーライドをリセットすることを確認し、またはあなたのテストスイートの残りの部分はまた、テストを使用している場合::ディープあなたはいくつかの奇妙な驚きを持っているかもしれません。

+0

回答のためのsimbabqueありがとうございます。 ハッシュ内のすべての配列参照を動的に処理するにはどうすればよいですか。 $ hash2が生成され、ネストされたハッシュを含んでいます。どのような配列の比較をバッグ経由で行うべきかを動的にcmp_deeplyに伝えるにはどうすればいいですか? – Girish

+0

おかげさまで@simbabque、どのように私は動的にハッシュ内のすべての配列参照を袋に入れますか? 'my $ arr_of_h1 = {'a' => [1,2,3]、b => [{2 => 1}、{1 => 1}、{3 => 1}]}; ' ' {'cmp_deeply({1}}、{1}、{2}、{3}、{1} $ strtは上で動作しますが、以下はバッグの比較を実行することで動作するようにしたいと考えています。 'cmp_deeply($ arr_of_h1、$ arr_of_h2、"ハッシュは等しい "); ' – Girish

+0

@user私はあなたがそれを構築しなければならないと思います。あるいは、いくつかのフックメカニズムがあります。あなたは完全なTest :: Deepドキュメントを読んだことがありますか?それ以外の場合は、https://metacpan.org/pod/Data::Visitorなどを使用して同様の方法でトラバーサルを構築できます。最初の質問とは違うので、新しい質問をすることをお勧めします。 – simbabque

関連する問題