perl deep-copy

¿Cuál es la mejor manera de copiar en profundidad un hash de hashes en Perl?



deep-copy (4)

Posible duplicado:
¿Cuál es la mejor manera de hacer una copia profunda de una estructura de datos en Perl?

Antes de comenzar a codificar esto 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'', }, }, );

A continuación, extraigo mi grupo de la configuración desreferenciando y cambiando los contenidos en tiempo de ejecución antes de volver a escribir el archivo de configuración:

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

El problema es que necesito verificar si se realizaron cambios y realizar cambios asociados a la estructura de archivos del sistema. No puedo hacer esto al verificar:

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

como $group{''item1''} y $config{''group''}{''item1''} son los mismos hashref.

Ahora bien, aunque sería 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 forma de deshacerse de una estructura de datos compleja anidada , copiando el contenido de los hash refs y no simplemente copiando las referencias. Un examen superficial en CPAN no enciende nada. ¿Qué me estoy perdiendo?

Punto de referencia

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)


Siempre podría almacenar el hash a través de Storable o Data :: Dumper, y reasignar 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) };


Estructura de datos profunda 101:

  • Utilice el dclone de dclone para hacer una copia profunda de una estructura y freeze y thaw para serializar / deserializarlas para el almacenamiento (por ejemplo, en una base de datos o una cookie http (pero debe encriptar todo lo que envíe al usuario para hacerlo más difícil) para manipular).
  • Utilice Data :: Compare (o Test :: Deep o Test :: Differences dentro de una prueba unitaria) para comparar dos estructuras de datos profundas.
  • Utilice 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 :)

use Storable qw(dclone); $group2 = dclone(/%group);


De la documentación de Storable :: dclone encontré Clone :

my $copy = clone (/@array); # or my %copy = %{ clone (/%hash) };

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