2009-08-13 7 views
10

Comment comparer deux hachages en Perl sans utiliser Data :: Compare?Comment comparer deux hachages en Perl sans utiliser Data :: Compare?

+12

Eh bien, vous regardez dans Data :: Compare et voyez ce qu'ils font. Pourquoi ne voulez-vous pas utiliser ce module? –

+0

Copie possible de [Perl - Comparer deux hash imbriqués] (https://stackoverflow.com/questions/37135504/perl-compare-two-nested-hash) –

Répondre

20

La meilleure approche diffère selon vos objectifs. L'élément FAQ mentionné par Sinan est une bonne ressource: How do I test whether two arrays or hashes are equal?. Au cours du développement et du débogage (et bien sûr lors de l'écriture de tests unitaires), j'ai trouvé Test::More utile lors de la comparaison de tableaux, de hachages et de structures de données complexes. Un exemple simple:

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'); 

Sortie:

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

On dirait que Test :: Deep a été inspiré par is_deeply. Ma question est de savoir comment faire cmp_deeply partie d'un test au lieu d'un test seul? Parce que ma liste de tests indique seulement 8, mais chaque fois que j'utilise cmp_deeply, ça compte comme un test, ce qui fait que mon nombre réel de tests 11 (parce que j'appelle cmp_deeply 3 fois) quand j'ai seulement 8 fonctions. Je ne veux pas augmenter le nombre de mes tests. Y a-t-il une solution plus viable? – biznez

+0

@yskhoo. Chaque fois que vous appelez l'une des fonctions de test ('ok',' cmp_deeply', etc.) cela compte comme un test. Pour autant que je sache, il n'y a pas moyen d'éviter cela. Si vous ne souhaitez pas valider à l'avance un certain nombre de tests, vous pouvez le faire lorsque vous chargez le module de test: 'use Test :: More qw (no_plan);'. – FMc

+5

Vous l'avez déjà demandé sur http://stackoverflow.com/questions/1274756/how-can-i-use-perls-testdeepcmpdeeply-without-increasing-the-test-count. Vous n'avez pas répondu pourquoi vous ne pouvez pas augmenter le nombre de tests, ou ce qui est si compliqué au sujet de votre structure de données que vous devez appeler cmp_deeply trois fois. Veuillez vous éloigner des questions que vous posez et déterminer quel est le véritable problème. Si vous fournissez plus d'informations, nous pouvons peut-être vous aider. – Ether

3

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

FAQ Perl et les réponses font partie de votre distribution Perl. Vous pouvez voir la version de cette réponse qui est venu avec votre perl en exécutant:

$ perldoc -q equal

dans votre terminal.

+0

Quelle est la différence entre cmpStr et cmpStrHard dans FreezeThaw? – biznez

10

Comparez n'est pas une phrase assez détaillée quand on parle de hash. Il existe plusieurs façons de comparer les hachages:

Ont-ils le même nombre de clés?

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

Les clés sont-elles identiques dans les deux hachages?

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"; 
    } 
} 

Ont-ils les mêmes clés et les mêmes valeurs dans les deux hachages?

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"; 
    } 
} 

Sont-ils isomorphes (je vais laisser celui-ci au lecteur que je ne veux pas particulièrement d'essayer sa mise en œuvre à partir de zéro)?

Ou une autre mesure d'égale?

Et, bien sûr, ce code ne traite que des hachages simples. L'ajout de structures de données complexes le rend encore plus complexe.

2

rapide, sale, et je suis sûr pas efficace:

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

Cette approche plus ['Text :: Diff'] (https://metacpan.org/module/Text::Diff) imprime un rapport utile. – Lumi

+2

Aussi, vous devriez faire 'local $ Data :: Dumper :: Sortkeys = 1;' pour assurer le même ordre des clés. – skaurus

+0

@skaurus: Pourquoi? Ne seraient-ils pas dans le même ordre? – zakovyrya

-1

Pour comparer:

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; 
} 

Création de hachage sans clés en double:

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

veuillez fournir une explication pour votre réponse. –

+0

d'où est venu $ key_name? – nurp

Questions connexes