2009-08-13 2 views
10

Как сравнить два хэша в Perl, не используя Data :: Compare?Как сравнить два хэша в Perl без использования Data :: Compare?

+12

Ну, вы смотрите в Data :: Сравните и посмотрите, что они делают. Почему вы не хотите использовать этот модуль? –

+0

Возможный дубликат [Perl - Сравнить два вложенных хэша] (https://stackoverflow.com/questions/37135504/perl-compare-two-nested-hash) –

ответ

20

Лучший подход отличается в зависимости от ваших целей. Вопрос о часто задаваемых вопросах, упомянутый Sinan, является хорошим ресурсом: How do I test whether two arrays or hashes are equal?. Во время разработки и отладки (и, конечно, при написании модульных тестов) я нашел Test::More полезной при сравнении массивов, хэшей и сложных структур данных. Простой пример:

use strict; 
use warnings; 

my %some_data = (
    a => [1, 2, 'x'], 
    b => { foo => 'bar', biz => 'buz' }, 
    j => '867-5309', 
); 

my %other_data = (
    a => [1, 2, 'x'], 
    b => { foo => 'bar', biz => 'buz' }, 
    j => '867-5309x', 
); 

use Test::More tests => 1; 
is_deeply(\%other_data, \%some_data, 'data structures should be the same'); 

Выход:

1..1 
not ok 1 - data structures should be the same 
# Failed test 'data structures should be the same' 
# at _x.pl line 19. 
#  Structures begin differing at: 
#   $got->{j} = '867-5309x' 
#  $expected->{j} = '867-5309' 
# Looks like you failed 1 test of 1. 
+2

Похоже, что Test :: Deep был вдохновлен is_deeply. Мой вопрос в том, как я могу сделать cmp_deeply частью теста вместо теста самостоятельно? Поскольку в моем списке тестов указано только 8, но каждый раз, когда я использую cmp_deeply, он считается тестом, который делает мое фактическое число тестов 11 (потому что я вызываю cmp_deeply 3 раза), когда у меня есть только 8 функций. Я не хочу увеличивать число моих тестов. Существует ли более жизнеспособное решение? – biznez

+0

@yskhoo. Каждый раз, когда вы вызываете одну из функций тестирования ('ok',' cmp_deeply' и т. Д.), Это считается тестом. Насколько я знаю, нет способа избежать этого. Если вы не хотите заранее фиксировать определенное количество тестов, вы можете сделать это при загрузке модуля тестирования: 'use Test :: More qw (no_plan);'. – FMc

+5

Вы уже спрашивали об этом в http://stackoverflow.com/questions/1274756/how-can-i-use-perls-testdeepcmpdeeply-without-increasing-the-test-count. Вы не ответили, почему вы не можете увеличить количество тестов, или то, что так сложно в вашей структуре данных, что вам нужно вызвать cmp_deeply три раза. Пожалуйста, отступите от вопросов, которые вы задаете, и определите, какова настоящая проблема. Если бы вы предоставили больше информации, возможно, мы сможем помочь. – Ether

3

См How do I test whether two arrays or hashes are equal?

FAQ Perl и ответы являются частью вас Perl распределения. Вы можете просмотреть версию этого ответа, который пришел с вашей perl команды:

$ perldoc -q equal

в вашем терминале.

+0

В чем разница между cmpStr и cmpStrHard в FreezeThaw? – biznez

10

Сравнить не достаточно детализированы фразу, когда речь идет о хэшей. Существует много способов сравнить хеши:

Есть ли у них одинаковое количество ключей?

if (%a == %b) { 
    print "they have the same number of keys\n"; 
} else { 
    print "they don't have the same number of keys\n"; 
} 

Являются ли ключи одинаковыми в обоих хешах?

if (%a != %b) { 
    print "they don't have the same number of keys\n"; 
} else { 
    my %cmp = map { $_ => 1 } keys %a; 
    for my $key (keys %b) { 
     last unless exists $cmp{$key}; 
     delete $cmp{$key}; 
    } 
    if (%cmp) { 
     print "they don't have the same keys\n"; 
    } else { 
     print "they have the same keys\n"; 
    } 
} 

Имеют ли они одинаковые ключи и одинаковые значения в обоих хешах?

if (%a != %b) { 
    print "they don't have the same number of keys\n"; 
} else { 
    my %cmp = map { $_ => 1 } keys %a; 
    for my $key (keys %b) { 
     last unless exists $cmp{$key}; 
     last unless $a{$key} eq $b{$key}; 
     delete $cmp{$key}; 
    } 
    if (%cmp) { 
     print "they don't have the same keys or values\n"; 
    } else { 
     print "they have the same keys or values\n"; 
    } 
} 

ли они изоморфные (я оставлю этот до читателя, как я не особо хочу попробовать реализовать его с нуля)?

Или какая-либо другая мера равных?

И, конечно же, этот код касается простых хэшей. Добавление сложных структур данных делает его еще более сложным.

2

Быстрая, грязная, и я уверен, что это не эффективно:

use strict; 
use warnings; 

use Data::Dumper; 

sub compare ($$) { 
    local $Data::Dumper::Terse = 1; 
    local $Data::Dumper::Indent = 0; 
    Dumper(shift) eq Dumper(shift); 
} 

my %a = (foo => 'bar', bar => [ 0 .. 3 ]); 
my %b = (foo => 'bar', bar => [ 0 .. 3 ]); 
my %c = (foo => 'bar', bar => [ 0 .. 4 ]); 

print Dumper compare \%a, \%b; 
print Dumper compare \%a, \%c; 
+1

Этот подход плюс ['Text :: Diff'] (https://metacpan.org/module/Text::Diff) печатает полезный отчет. – Lumi

+2

Также вы должны сделать 'local $ Data :: Dumper :: Sortkeys = 1;' для обеспечения того же порядка ключей. – skaurus

+0

@skaurus: Почему? Разве они не были бы в одном порядке? – zakovyrya

-1

Для сравнения:

sub HashCompare { 
    my ($a, $b) = @_; 
    my %rhash_1 = %$a; 
    my %rhash_2 = %$b; 

    my $key   = undef; 
    my $hash_2_line = undef; 
    my $hash_1_line = undef; 

    foreach $key (keys(%rhash_2)) { 
    if (exists($rhash_1{$key})) { 
    if ($rhash_1{$key} ne $rhash_2{$key}) { 
    print "key $key in $file_1 = $rhash_1{$key} & $rhash_2{$key} in $file_2\n"; 
     } 
     } 
    } 
    else { 
     print "key $key in $file_1 is not present in $file_2\n"; 

      #next; 
     } 
    } 

    foreach my $comp_key (keys %rhash_1) { 
     if (!exists($rhash_2{$comp_key})) { 
      print MYFILE "key $comp_key in $file_2 is not present in $file_1\n"; 
     } 
    } 
    return; 
} 

Создание хэша, без дубликатов ключей:

sub CreateHash { 
    my (@key_val_file) = @_; 
    my $key_count  = 1; 
    my %hash_key_val =(); 
    my $str4   = undef; 

    local $/ = undef; 

    foreach my $each_line (@key_val_file) { 
      @key_val = split(/,/, $each_line); 
      if (exists($hash_key_val{$key_val[0]})) { 
        $key_count = $key_count + 1; 
        $str4  = $key_val[0] . " occurence-" . $key_count; 
        $hash_key_val{$str4} = $key_val[1]; 
       } 
       else { 
        $hash_key_val{$key_name} = $key_val[1]; 
       } 
      } 
     } 

     $key_count = 1; 

    close FILE; 

    return %hash_key_val; 
} 
+0

, пожалуйста, объясните свой ответ. –

+0

Откуда взялось $ key_name? – nurp

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