2009-10-09 5 views
22

Powiel możliwe:
What's the best way to make a deep copy of a data structure in Perl?Jaki jest najlepszy sposób na głębokie kopiowanie mieszania haszy w Perlu?

Zanim zacznę kodujący ten sam i wyważania otwartych drzwi, jak można skopiować hash mieszań nie powielając hashrefs?

Przeczytałem skrót mieszania haszy przez Config::General. czyli struktura danych jest:

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

I wtedy ciągnąć moją grupę od konfiguracji przez dereferencji go i zmienić zawartość w czasie wykonywania przed przepisanie pliku config:

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

Problem polega na tym, że Należy sprawdzić, czy zmiany zostały wprowadzone i dokonać odpowiednich zmian w strukturze plików systemu. Nie mogę tego zrobić poprzez sprawdzenie:

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

jak $group{'item1'} i $config{'group'}{'item1'} są zarówno dokładnie to samo hashref.

Teraz powinno być trywialnie po prostu ponowne przeanalizowanie pliku konfiguracyjnego i porównanie przeanalizowanej kopii z dysku do wersji edytowanej tuż przed zapisaniem na dysk, jestem pewien, że istnieje sposób na zagnieżdżoną dereferencję złożona struktura danych, kopiowanie zawartości haseł, a nie tylko kopiowanie samych referencji. Pobieżne badanie CPAN niczego nie zmienia. czego mi brakuje?

Benchmark

Got Moja odpowiedź:

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

wyniki:

 
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

Jeśli, jak mówisz, otrzymałeś odpowiedź, powinieneś sprawdzić wpis, który odpowiedział na twoje pytanie jako poprawną odpowiedź. –

Odpowiedz

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

zawsze można przechowywać hash poprzez magazynować lub Dane :: Dumper, a przeniesiony zapisaną wartość do nowego skrótu. To powinno uzyskać pełną kopię bez utrzymywania odnośników.

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

Istnieje specjalna funkcja 'dclone' dla tego przypadku –

29

Z dokumentacji Chowany :: dclone znalazłem Clone:

my $copy = clone (\@array); 

# or 

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

Nie potrzebują elastyczności, i twierdzi, że jest szybszy niż Storable::dclone.

+2

Benchmark pokazuje, że jest około dwa razy szybszy niż dclone – Oesor

+0

wygląda tak, jak nie robi nici z klonowaniem :: współdzielone dane strucutre? Nie można zlokalizować metody obiektowej "FETCH" za pośrednictwem pakietu "threads :: shared :: tie" – ealeon

7

Głęboka struktura danych 101:

  • Zastosowanie Storable „s dclone aby głęboką kopię struktury i freeze i thaw do serializacji/deserializacji ich przechowywania (powiedzmy w bazie danych, lub http cookie (ale należy zaszyfrować wszystko, co wysyłasz do użytkownika, aby utrudnić manipulowanie).
  • Użyj Data::Compare (lub Test::Deep lub Test::Differences wewnątrz testu urządzenia), aby porównać dwie głębokie struktury danych.
  • Podczas debugowania użyj Data::Dumper lub Data::Dump, aby zobaczyć, jak wyglądają Twoje obiekty. Ale nie używaj tego jako licencji do manipulowania wewnętrznymi obiektami innego obiektu; użyj interfejsu API. :)
+1

Dane :: Porównaj też mnie nowe, właśnie rozwijam swoje skróty, aby je sprawdzić. Na pewno spróbuję trochę czasu, by porównać naprawdę skomplikowane rzeczy; dzięki – Oesor

+1

Test :: Deep i Test :: Differences spadają z łask ze względu na wszechobecną funkcję Test :: More is_deeply - sprawdź to. Brud prosty w użyciu, a otrzymasz ładny błąd. –