Perl - 比较两个嵌套哈希
Perl - Compare two nested hash
这是我的场景,其中有 2 个哈希值已从 2 个 JSON 文件中解码。
我有 2 个复杂的哈希,
$hash1 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v1, v2, v3] }}
$hash2 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v3, v2, v1] }}
我想比较这 2 个散列是否相等,并使用 Data::Compare 的比较和 Test::More 的 is_deeply。两者都不忽略数组的顺序。
我想比较忽略键 'k21'.
的数组值的顺序
我的应用程序从 'keys %hash' 填充数组,该数组给出随机顺序。
已尝试 'ignore_hash_keys' 个 Data::Compare,但我的哈希有时可能很复杂,不想忽略。
键 'k21' 有时也可以有哈希数组。
$hash3 = {k1=> { k11 => v1}, k2 => { k21 => [{v3 => v31}, {v2 => v22}] }}
如何通过忽略数组顺序来比较如此复杂的散列。
可以使用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,它忽略了元素的顺序。
This does a bag comparison, that is, it compares two arrays but ignores the order of the elements [...]
更新:来自:
How do I bag all array references inside hash dynamically
对 Test::Deep 代码的一些挖掘表明可以覆盖它。我看了at Test::Deep itself first, and found that there is a Test::Deep::Array, which deals with arrays. All of the packages that handle stuff inside of T::D have a descend
method。所以这就是我们需要挂钩的地方。
Sub::Override 非常适合临时覆盖内容,而不是弄乱 typeglobs。
基本上我们需要做的就是将 Test::Deep::Array::descend
最后一行中对 Test::Deep::arrayelementsonly
的调用替换为对 bag()
的调用。其余的只是复制(缩进是我的)。对于小型 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
或让它超出范围来重置覆盖 ,否则如果测试套件的其余部分,您可能会遇到一些奇怪的惊喜也使用 Test::Deep.
这是我的场景,其中有 2 个哈希值已从 2 个 JSON 文件中解码。
我有 2 个复杂的哈希,
$hash1 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v1, v2, v3] }}
$hash2 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v3, v2, v1] }}
我想比较这 2 个散列是否相等,并使用 Data::Compare 的比较和 Test::More 的 is_deeply。两者都不忽略数组的顺序。
我想比较忽略键 'k21'.
的数组值的顺序
我的应用程序从 'keys %hash' 填充数组,该数组给出随机顺序。
已尝试 'ignore_hash_keys' 个 Data::Compare,但我的哈希有时可能很复杂,不想忽略。
键 'k21' 有时也可以有哈希数组。
$hash3 = {k1=> { k11 => v1}, k2 => { k21 => [{v3 => v31}, {v2 => v22}] }}
如何通过忽略数组顺序来比较如此复杂的散列。
可以使用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,它忽略了元素的顺序。
This does a bag comparison, that is, it compares two arrays but ignores the order of the elements [...]
更新:来自
How do I bag all array references inside hash dynamically
对 Test::Deep 代码的一些挖掘表明可以覆盖它。我看了at Test::Deep itself first, and found that there is a Test::Deep::Array, which deals with arrays. All of the packages that handle stuff inside of T::D have a descend
method。所以这就是我们需要挂钩的地方。
Sub::Override 非常适合临时覆盖内容,而不是弄乱 typeglobs。
基本上我们需要做的就是将 Test::Deep::Array::descend
最后一行中对 Test::Deep::arrayelementsonly
的调用替换为对 bag()
的调用。其余的只是复制(缩进是我的)。对于小型 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
或让它超出范围来重置覆盖 ,否则如果测试套件的其余部分,您可能会遇到一些奇怪的惊喜也使用 Test::Deep.