2016-05-10 137 views
2

这是我的场景,其中有2个哈希已经从2个JSON文件解码。Perl - 比较两个嵌套哈希

我有2个复杂的哈希,

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

我想比较这两个哈希平等,并用比较数据::测试的比较和is_deeply ::更多。两者都不会忽略数组的顺序。
我想比较忽略键'k21'的数组值的顺序。
我的应用程序从'keys%hash'填充数组,给出随机顺序。
尝试了Data :: Compare的'ignore_hash_keys',但我的散列有时可能很复杂,不想忽略。

密钥'k21'有时也可以有散列数组。

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

如何通过忽略数组顺序来比较这种复杂的散列。

回答

5

您可以使用Test::Deep,它提供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是很好的暂时覆盖的东西,而不是混乱与typeglobs。

基本上我们所需要做的就是用电话号码bag()替换Test::Deep::arrayelementsonlyTest::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说任何数组比较应该通过bag来完成,还是应该遍历散列并进行单独的包比较。 – Girish

+0

Thanks @simbabque,如何动态地在散列内部收集所有数组引用。 'my $ arr_of_h1 = {'a'=> [1,2,3],b => [{2 => 1},{1 => 1},{3 => 1}]};' ' my $ arr_of_h2 = {'a'=> [1,2,3],b => [{2 => 1},{3 => 1},{1 => 1}]};' 'cmp_deeply $ arr_of_h1 - > {b},bag(@ {$ arr_of_h2 - > {b}}),“Array are equal”);' 上面的stmt工作,但想通过执行bag比较工作在下面。 'cmp_deeply($ arr_of_h1,$ arr_of_h2,“哈希值相等”);' – Girish

+0

@user我认为您将不得不构建它。或者也许有一些挂钩机制。您是否阅读完整的Test :: Deep文档?否则,你可以使用https://metacpan.org/pod/Data::Visitor或类似的东西来构建遍历。我建议你问一个新的问题,因为它与这里最初的问题不同。 – simbabque