2009-02-12 19 views
8

Me pregunto si existe un paquete idiomático de una sola línea o un paquete/función de distribución estándar que pueda usar para comparar dos hashes de Perl con solo tipos incorporados y no bendecidos. Los hash no son idénticos (no tienen direcciones de memoria equivalentes).¿Cómo hago una comparación de equivalencia de hash Perl simple?

Me gustaría saber la respuesta tanto para los hashes superficiales como para los hash con colecciones anidadas, pero entiendo que los hashes poco profundos pueden tener una solución mucho más simple.

TIA!

Respuesta

13

Algo así como cmp_deeply disponible en Test::Deep?

+1

Claro, creo que Test :: Deep :: eq_deeply es exactamente lo que estoy buscando. – cdleary

1

No sé si hay una forma fácil o un paquete incorporado, y no sé qué sucede cuando solo hace %hash1 == %hash2 (pero probablemente no sea así), pero no es terriblemente difícil rodar su poseer:

sub hash_comp (\%\%) { 
    my %hash1 = %{ shift }; 
    my %hash2 = %{ shift }; 
    foreach (keys %hash1) { 
    return 1 unless defined $hash2{$_} and $hash1{$_} == $hash2{$_}; 
    delete $hash1{$_}; 
    delete $hash2{$_}; 
    } 
    return 1 if keys $hash2; 
    return 0; 
} 

no probado, pero debe devolver 0 si los hashes tienen todos los mismos elementos y todos los mismos valores. Esta función deberá modificarse para tener en cuenta hashes multidimensionales.

Si quiere algo de una distribución estándar, puede use Data::Dumper; y simplemente volcar los dos hashes en dos variables escalares, luego compare las cadenas para la igualdad. Aquello podría funcionar.

También hay un paquete en CPAN llamado FreezeThaw que parece que hace lo que quiere.

Tenga en cuenta que para usar la coincidencia inteligente (no se repite aquí porque ya está publicada), tendrá que use feature; y solo está disponible para Perl 5.10. Pero, ¿quién sigue usando Perl 5.8.8, verdad?

+1

"¿Pero quién todavía está usando Perl 5.8.8, verdad?" Yo soy. :-) – cdleary

+0

También la comparación "==" fuerza un contexto escalar, por lo que compara el número de elementos. – cdleary

+0

@cdleary: Lo dije porque, como usuario de Mac OS X, todos los usuarios de OS X están utilizando de forma predeterminada 5.8.8, a menos que se hayan tomado la molestia de actualizarlo. –

4

[Esta fue una respuesta a una respuesta por alguien que suprime la respuesta.]

Uh oh!

%a ~~ %b && [sort values %a] ~~ [sort values %b] 

no comprueba si los valores pertenecen a las mismas teclas.

#! perl 
use warnings; 
use strict; 

my %a = (eat => "banana", say => "whu whu"); # monkey 
my %b = (eat => "whu whu", say => "banana"); # gorilla 
print "Magilla Gorilla is always right\n" 
    if %a ~~ %b && [sort values %a] ~~ [sort values %b]; 
+0

'Tis es un valiente programador de Perl de proporciones épicas que se atreve a usar el operador de sabelotodo '~~'. :) – tchrist

0

Para los hashes de poca profundidad:

(grep {exists %hash2{$_}} keys %hash1) > 0 
0

hashes se puede lanzar en matrices, donde cada valor sigue su clave (pero no sabrán el orden de las teclas). Por lo tanto:

(join("",sort(%hash1)) eq join("",sort(%hash2))) 

Oh, espera, que no funciona porque hay algunos casos extremos, como:

%hash1 = { 'aaa' => 'aa' }; 
%hash2 = { 'aa' => 'aaa' }; 

así que lo mejor es utilizar un personaje de la join() que sabe que nunca aparezca en ninguna clave o valor. Si los valores son BLOB, ese será un gran problema, pero para cualquier otra cosa podría usar el carácter NULL "\ 0".

(join("\0",sort(%hash1)) eq join("\0",sort(%hash2))) 

parece un poco feo, lo sé, pero lo hará para comprobar si dos valores hash son iguales de una manera superficial, que es lo que la mayoría de la gente está buscando.

-1

convertir archivos hash a xml y comparar, y sí, podría usar multinivel.

sub isEqualHash 
{ 
    my ($self,$hash1, $hash2) = @_; 
    my $file1 = "c:/neo-file1.txt"; 
    my $file2 = "c:/neo-file2.txt"; 
    my $xmlObj = XML::Simple->new(); 
    my $dummy_file = $xmlObj->XMLout($hash1,OutputFile => $file1); 
    my $dummy_file = $xmlObj->XMLout($hash2,OutputFile => $file2); 

    open FILE, "<".$file1; 
    my $file_contents1 = do { local $/; <FILE> }; 
    close(FILE); 

    open FILE, "<".$file2; 
    my $file_contents2 = do { local $/; <FILE> }; 
    close(FILE); 

    if($file_contents1 eq $file_contents2) 
    { 
     return "Passed"; 
    } 
    else 
    { 
     return "Failed"; 
    } 
} 
1

Gracias por su pregunta.

He usado Test :: More :: eq_hash como resultado.

Cuestiones relacionadas