2009-08-13 5 views
10

Wie kann ich zwei Hashes in Perl ohne Verwendung von Data :: Compare vergleichen?Wie kann ich zwei Hashes in Perl vergleichen, ohne Data :: Compare zu verwenden?

+12

Nun, Sie sehen in Daten :: Vergleichen und sehen, was sie tun. Warum willst du dieses Modul nicht benutzen? –

+0

Mögliches Duplikat von [Perl - Vergleiche zwei verschachtelte Hashs] (https://stackoverflow.com/questions/37135504/perl-compare-two-nested-hash) –

Antwort

20

Der beste Ansatz unterscheidet sich je nach Ihren Zwecken. Der von Sinan erwähnte FAQ-Artikel ist eine gute Quelle: How do I test whether two arrays or hashes are equal?. Während der Entwicklung und des Debugging (und natürlich beim Schreiben von Komponententests) habe ich festgestellt, dass Test::More beim Vergleich von Arrays, Hashes und komplexen Datenstrukturen nützlich ist. Ein einfaches Beispiel:

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

Ausgang:

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

Es sieht so aus, als ob Test :: Deep von is_deeply inspiriert wurde. Meine Frage ist, wie mache ich Cmp_deeply Teil eines Tests statt eines Tests für sich allein? Weil meine Liste von Tests nur 8 angibt, aber jedes Mal, wenn ich cmp_deeply verwende, zählt es als ein Test, was meine tatsächliche Anzahl von Tests 11 macht (weil ich cmp_deeply 3 Mal aufrufen), wenn ich nur 8 Funktionen habe. Ich möchte die Anzahl meiner Tests nicht erhöhen. Gibt es eine praktikablere Lösung? – biznez

+0

@yskhoo. Jedes Mal, wenn Sie eine der Testfunktionen aufrufen ('ok',' cmp_deeply' usw.), zählt dies als Test. Soweit ich weiß, gibt es keinen Weg, das zu vermeiden. Wenn Sie nicht im Voraus eine bestimmte Anzahl von Tests festlegen möchten, können Sie dies tun, wenn Sie das Testmodul laden: 'verwenden Sie Test :: More qw (no_plan);'. – FMc

+5

Sie haben dies bereits in http://stackoverflow.com/questions/1274756/how-cani-i-use-perls-testdeepcmpdeeply-without-creasing-the-test-count gefragt. Sie haben nicht geantwortet, warum Sie die Anzahl der Tests nicht erhöhen können oder was an Ihrer Datenstruktur so kompliziert ist, dass Sie cmp_deeply dreimal aufrufen müssen. Bitte treten Sie zurück von den Fragen, die Sie stellen, und bestimmen Sie, was das eigentliche Problem ist. Wenn Sie mehr Informationen zur Verfügung stellen, können wir Ihnen vielleicht helfen. – Ether

3

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

Perl FAQ und Antworten sind ein Teil von Ihnen Perl-Distribution. Sie können die Version dieser Antwort anzeigen, indem Sie mit Ihrem perl kam:

$ perldoc -q equal

in Ihrem Terminal.

+0

Was ist der Unterschied zwischen cmpStr und cmpStrHard in FreezeThaw? – biznez

10

vergleichen ist nicht detailliert genug, um Ausdruck, wenn es um Hashes zu reden. Es gibt viele Möglichkeiten, Hashes zu vergleichen:

Haben sie die gleiche Anzahl von Schlüsseln?

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

Sind die Tasten in beiden Hashes identisch?

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

Haben sie die gleichen Schlüssel und die gleichen Werte in beiden Hashes?

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

Sind sie isomorph (Ich werde diese ein dem Leser überlassen, wie ich vor allem nicht, es von Grund auf neu versuchen wollen Implementierung)?

Oder ein anderes Maß von gleich?

Und natürlich befasst sich dieser Code nur mit einfachen Hashes. Das Hinzufügen komplexer Datenstrukturen macht es noch komplexer.

2

Schnell, schmutzig, und ich bin sicher nicht so effizient:

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

Dieser Ansatz plus ['Text :: Diff '] (https://metacpan.org/module/Text::Diff) gibt einen nützlichen Bericht aus. – Lumi

+2

Sie sollten auch 'local $ Data :: Dumper :: Sortkeys = 1;' ausführen, um die gleiche Reihenfolge der Schlüssel zu gewährleisten. – skaurus

+0

@skaurus: Warum? Wären sie nicht in der gleichen Reihenfolge? – zakovyrya

-1

Zum Vergleich:

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

Erstellen Hash ohne Nachschlüssel:

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

Bitte geben Sie eine Erklärung für Ihre Antwort. –

+0

Woher kam $ key_name? – nurp

1

hat die gleiche Funktionalität.

Verwandte Themen