2009-10-09 8 views
22

Eventuali duplicati:
What's the best way to make a deep copy of a data structure in Perl?Qual è il modo migliore per copiare in profondità un hash di hash in Perl?

Prima di iniziare la codifica questo me stesso e reinventare la ruota, come si fa a copiare un hash di hash senza duplicare le hashrefs?

Sto leggendo un hash di hash di hash via Config::General. vale a dire, la struttura dei dati è:

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

Ho poi tirare il mio gruppo dal config dereferenziando e cambiare il contenuto in fase di esecuzione prima di riscrivere il file di configurazione:

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

Il problema è che io è necessario verificare se sono state apportate modifiche e apportare modifiche associate alla struttura del file del sistema. Non posso farlo controllando:

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

come $group{'item1'} e $config{'group'}{'item1'} sono entrambi la stessa identica rifhash.

Ora, mentre dovrebbe essere banale riassociare semplicemente il file di configurazione e confrontare la copia analizzata dal disco con la versione modificata appena prima del salvataggio su disco, sono sicuro che c'è un modo per un dereferenziamento annidato di una complessa struttura dati, che copia i contenuti degli hash ref e non copia semplicemente i riferimenti stessi. Un esame superficiale su CPAN non trasforma nulla. Cosa mi manca?

Benchmark

avuto la mia risposta:

#!/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 }}, 
}); 

risultati in:

 
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

Se, come dici tu, hai la tua risposta, dovresti controllare il post che ha risposto alla tua domanda come risposta corretta. –

risposta

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

sempre potuto archiviare l'hash tramite riponibile o Data :: Dumper e riassegnato il valore memorizzato in un nuovo hash. Questo dovrebbe ottenere una copia completa senza mantenere i collegamenti di riferimento.

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

In questo caso è presente la funzione speciale 'dclone' –

29

Dalla documentazione riponibile :: dclone ho trovato Clone:

my $copy = clone (\@array); 

# or 

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

Non hanno bisogno di flessibilità, e sostiene di essere più veloce di Storable::dclone.

+2

Il benchmark mostra che è circa il doppio della velocità di dclone – Oesor

+0

sembra come questo non clone threads :: shared data strucutre? Impossibile trovare il metodo dell'oggetto "FETCH" tramite il pacchetto "threads :: shared :: tie" – ealeon

7

struttura dati profonda 101:

  • Usa Storable s' dclone per fare una copia completa di una struttura, e freeze e thaw per serializzare/li deserializzare per l'archiviazione (per esempio in un database, o un http cookie (ma dovresti cifrare qualsiasi cosa tu invii all'utente per renderlo più difficile da manomettere).
  • Utilizzare Data::Compare (o Test::Deep o Test::Differences all'interno di un test di unità) per confrontare due strutture di dati profonde.
  • Utilizzare Data::Dumper o Data::Dump nel debug per vedere come sono gli oggetti. Ma non usarlo come una licenza per manomettere gli interni di un altro oggetto; usa l'API. :)
+1

Data: Compare anche per Compare, sono stato appena srotolato i miei hash per verificarli. Sarò sicuro di provare un po 'di tempo per confrontare cose davvero complicate; grazie – Oesor

+1

Test :: Deep e Test :: Le differenze stanno cadendo in disgrazia a causa dell'onnipresente funzionalità di Test :: More is_deeply - verificarlo. Sporco semplice da usare, e ottieni un bel errore. –