2009-08-13 14 views
10

Come faccio a confrontare due hash in Perl senza usare Data :: Compare?Come faccio a confrontare due hash in Perl senza usare Data :: Compare?

+12

Bene, si guarda in Dati :: Confronta e guarda cosa fanno. Perché non vuoi usare quel modulo? –

+0

Possibile duplicato di [Perl - Confronta due hash nidificati] (https://stackoverflow.com/questions/37135504/perl-compare-two-ested-hash) –

risposta

20

L'approccio migliore differisce in base ai propri scopi. L'elemento FAQ menzionato da Sinan è una buona risorsa: How do I test whether two arrays or hashes are equal?. Durante lo sviluppo e il debug (e ovviamente durante la scrittura dei test unitari) ho trovato che Test::More è utile quando si confrontano matrici, hash e strutture dati complesse. Un semplice esempio:

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

uscita:

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

Sembra che Test :: Deep sia stato ispirato da is_deeply. La mia domanda è: come faccio a rendere cmp_deeply parte di un test invece di un test da solo? Perché la mia lista di test dice solo 8, ma ogni volta che uso cmp_deeply, conta come un test, rendendo il mio numero effettivo di test 11 (perché chiamo cmp_deeply 3 volte) quando ho solo 8 funzioni. Non voglio aumentare il numero dei miei test. C'è una soluzione più praticabile? – biznez

+0

@yskhoo. Ogni volta che chiami una delle funzioni di test ('ok',' cmp_deeply', ecc.) Conta come un test. Per quanto ne so, non c'è un modo per evitarlo. Se non si desidera eseguire il commit in anticipo su un numero specifico di test, è possibile farlo quando si carica il modulo di test: 'use Test :: More qw (no_plan);'. – FMc

+5

L'hai già chiesto in http://stackoverflow.com/questions/1274756/how-can-i-use-perls-testdeepcmpdeeply-without-increasing-the-test-count. Non hai risposto perché non è possibile aumentare il numero di test o la complessità della struttura dei dati che è necessario chiamare per tre volte cmp_deeply. Per favore, fai un passo indietro dalle domande che stai ponendo e determina quale sia il vero problema. Se vuoi fornire ulteriori informazioni, forse possiamo aiutarti. – Ether

3

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

FAQ di Perl e le risposte sono parte di te la distribuzione Perl. È possibile visualizzare la versione di questa risposta fornita con il perl eseguendo:

$ perldoc -q equal

nel terminale.

+0

Qual è la differenza tra cmpStr e cmpStrHard in FreezeThaw? – biznez

10

Confronta non è una frase abbastanza dettagliate quando si parla di hash. Esistono molti modi per confrontare gli hash:

Hanno lo stesso numero di chiavi?

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

Le chiavi sono le stesse in entrambi gli hash?

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

Hanno le stesse chiavi e gli stessi valori in entrambi gli hash?

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

Sono essi isomorfe (io lasciare questo uno fino al lettore come non ho particolarmente voglia di provare l'attuazione da zero)?

O qualche altra misura di uguale?

E, ovviamente, questo codice riguarda solo gli hash semplici. L'aggiunta di strutture dati complesse lo rende ancora più complesso.

2

rapida, sporco, e sono sicuro che non efficiente:

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

Questo approccio più ['Testo :: Diff'] (https://metacpan.org/module/Text::iff) stampa un rapporto utile. – Lumi

+2

Inoltre dovresti fare 'local $ Data :: Dumper :: Sortkeys = 1;' per garantire lo stesso ordine delle chiavi. – skaurus

+0

@skaurus: perché? Non sarebbero nello stesso ordine? – zakovyrya

-1

per il confronto:

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

Creazione di hash senza chiavi duplicate:

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

si prega di fornire una spiegazione per la risposta. –

+0

da dove proviene $ key_name? – nurp

Problemi correlati