2009-10-09 19 views
22

Duplicar posible:
What's the best way to make a deep copy of a data structure in Perl?¿Cuál es la mejor manera de copiar en profundidad un hash de hashes en Perl?

Antes de que comience la codificación de esto mismo y reinventar la rueda, ¿cómo se copia un hash de hashes sin duplicar los hashrefs?

Estoy leyendo un hash de hash de hashes a través de Config::General. es decir, la estructura de datos es:

my %config = (group => { item1 => { foo => 'value', 
            bar => 'value', 
            }, 
          item2 => { foo => 'value', 
            bar => 'value', 
            }, 
          item3 => { foo => 'value', 
            bar => 'value', 
            }, 
         }, 
      ); 

entonces saco mi grupo de la configuración desreferenciando y cambiar el contenido en tiempo de ejecución antes de volver a escribir el fichero de configuración:

my %group = %{$config{'group'}}; 

El problema es que yo necesita verificar si se hicieron cambios y realizar cambios asociados a la estructura de archivos del sistema. No puedo hacer esto comprobando:

if ($group{'item1'}{'foo'} ne $config{'group'}{'item1'}{'foo'}) { 
    ### Stuff! 
} 

como $group{'item1'} y $config{'group'}{'item1'} son ambos exactamente el mismo hashref.

Ahora bien, aunque debería ser trivial simplemente volver a analizar el archivo de configuración y comparar la copia analizada del disco con la versión editada justo antes de guardarla en el disco, estoy seguro de que hay una manera de eliminar una referencia anidada de una estructura de datos compleja, copiando los contenidos de los hash refs y no simplemente copiando las referencias. Un examen superficial en CPAN no enciende nada. ¿Qué me estoy perdiendo?

Benchmark

Tengo mi respuesta:

#!/usr/bin/perl 

use Benchmark qw(:all) ; 
use Storable qw(dclone); 
use Clone qw(clone); 

my %config = (group => { item1 => { foo => 'value', 
            bar => 'value', 
            }, 
          item2 => { foo => 'value', 
            bar => 'value', 
            }, 
          item3 => { foo => 'value', 
            bar => 'value', 
            }, 
         }, 
      ); 

my $ref = $config{'group'}; 

timethese(100000, { 
    'Clone' => sub { my %group = %{ clone $ref }}, 
    'Storable' => sub { my %group = %{ dclone $ref }}, 
}); 

resultados en:

 
Benchmark: timing 100000 iterations of Clone, Storable... 
    Clone: 2 wallclock secs (2.26 usr + 0.01 sys = 2.27 CPU) @ 44052.86/s (n=100000) 
Storable: 5 wallclock secs (4.71 usr + 0.02 sys = 4.73 CPU) @ 21141.65/s (n=100000) 
+2

Si, como dices, tienes tu respuesta, deberías revisar la respuesta correcta a la que respondió a tu pregunta. –

Respuesta

33
use Storable qw(dclone); 
$group2 = dclone(\%group); 
-3

siempre se puede almacenar el hash a través almacenable o Data :: Dumper, y reasignados el valor almacenado en un nuevo hash. Esto debería obtener una copia completa sin mantener los enlaces a los que se hace referencia.

use Storable; 
my $serialized = freeze \%config; 
my %newconfig = %{ thaw($serialized) }; 
+3

Hay una función especial 'dclone' para este caso –

29

De la documentación almacenable :: dclone encontré Clone:

my $copy = clone (\@array); 

# or 

my %copy = %{ clone (\%hash) }; 

No necesitan flexibilidad, y afirma ser más rápido que Storable::dclone.

+2

El índice de referencia muestra que esto es aproximadamente el doble de rápido que dclone – Oesor

+0

parece que esto no clona threads :: shared data strucutre? No se puede encontrar el método del objeto "FETCH" a través del paquete "threads :: shared :: tie" – ealeon

7

estructura de datos Profundo 101:

  • Uso Storable 's dclone para hacer una copia profunda de una estructura, y freeze y thaw para serializar/deserializar para el almacenamiento (por ejemplo, en una base de datos, o un http cookie (pero debe encriptar todo lo que envíe al usuario para dificultar su manipulación).
  • Utilice Data::Compare (o Test::Deep o Test::Differences dentro de una prueba unitaria) para comparar dos estructuras de datos profundas.
  • Use Data::Dumper o Data::Dump en la depuración para ver cómo se ven sus objetos. Pero no lo use como una licencia para manipular las partes internas de otro objeto; usa la API :)
+1

Data :: Compare también es nuevo para mí, solo he estado desenrollando mis hashes para verificarlos. Me aseguraré de probarlo algún tiempo para comparar cosas realmente complicadas; gracias – Oesor

+1

Test :: Deep, and Test :: Las diferencias están cayendo en desgracia debido a la ubicua funcionalidad nueva de Test :: More is_deeply - compruébalo. Suciedad simple de usar, y obtienes un bonito error. –

Cuestiones relacionadas