2016-05-10 2 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] }} 

Я хочу сравнить эти 2 хэш равенства и использовал сравнение Данных :: Сравнение и is_deeply Теста :: Больше. Оба не игнорируют порядок массива.
Я хочу сравнить игнорирование порядка значений массива ключа 'k21'.
Мое приложение заполняет массив из «ключей% hash», который дает случайный порядок.
Tried 'ignore_hash_keys' данных :: Compare, но мой хэш иногда может быть сложным и не хочет игнорировать.

Ключ «k21» также может иметь массив хешей.

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

Как сравнить такой сложный хеш, игнорируя порядок массива.

ответ

5

Вы можете использовать Test::Deep, который обеспечивает cmp_deeply. Это намного более универсальный, чем Test :: More's 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, который игнорирует порядок элементов.

Это делает сравнение мешок, который он сравнивает два массива, но игнорирует порядок элементов [...]


Update: От your comment:

Как суммировать все массивные ссылки внутри хэш динамически

Некоторые копания в коде Test :: Deep показали, что его можно перезаписать. Сначала я посмотрел at Test::Deep и обнаружил, что есть Test::Deep::Array, в котором рассматриваются массивы. Все пакеты, которые обрабатывают вещи внутри T :: D, имеют a descend method. Так вот где нам нужно зацепить.

Sub::Override отлично подходит для временного переопределения вещей, вместо того, чтобы возиться с typeglobs.

В основном все, что нам нужно сделать, это заменить вызов на Test::Deep::arrayelementsonly в окончательной строке Test::Deep::Array::descend с вызовом 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.

+0

Спасибо simbabque за ответ, Как суммировать все массивные ссылки внутри хэша динамически. $ hash2 выводится и содержит вложенный хеш, как я могу динамически сказать cmp_deeply, что любое сравнение массива должно выполняться через сумку, или я должен пересекать хэш и делать сравнения отдельных сумм. – Girish

+0

Спасибо @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 равны"); ' Выше stmt работает, но ниже нужно работать, выполняя сравнения пакетов. 'cmp_deeply ($ arr_of_h1, $ arr_of_h2," Hash равны ");' – Girish

+0

@user Я думаю, вам нужно будет это построить. Или, может быть, есть механизм зацепления. Вы читали полные документы Test :: Deep? В противном случае вы можете использовать https://metacpan.org/pod/Data::Visitor или что-то подобное для построения обхода. Я предлагаю вам задать новый вопрос для этого, так как он отличается от начального вопроса здесь. – simbabque

Смежные вопросы