2009-10-09 7 views
22

Possible en double:
What's the best way to make a deep copy of a data structure in Perl?Quelle est la meilleure façon de copier en profondeur un hachage de hachage en Perl?

Avant de commencer à coder moi-même et de réinventer la roue, comment copier-vous un hachage de hachages sans dupliquer les hashrefs?

Je lis un hachage de hachage de hachages via Config::General. à savoir, la structure de données est:

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

je puis tirer mon groupe de la configuration par déréférencement et modifier le contenu lors de l'exécution avant la réécriture du fichier de configuration:

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

Le problème est que je Vous devez vérifier si des modifications ont été apportées et apporter des modifications associées à la structure de fichier du système. Je ne peux pas faire cela en vérifiant:

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

comme $group{'item1'} et $config{'group'}{'item1'} sont à la fois la même hashref exacte.

Maintenant, s'il est trivial de simplement analyser à nouveau le fichier de configuration et de comparer la copie analysée du disque avec la version modifiée juste avant de l'enregistrer sur le disque, je suis sûr qu'il existe un moyen de déréférencer imbriqué une structure de données complexe, copiant le contenu des références de hachage et ne copiant pas simplement les références elles-mêmes. Un examen superficiel du CPAN ne change rien. Qu'est-ce que je rate?

Benchmark

eu ma réponse:

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

résultats dans:

 
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, comme vous le dites, vous avez obtenu votre réponse, vous devriez vérifier la réponse à votre question. –

Répondre

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

pouvez toujours stocker le hachage via stockable ou Data :: Dumper et réaffecté la valeur stockée dans un nouveau hachage. Cela devrait obtenir une copie complète sans maintenir les liens référencés.

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

Il y a une fonction spéciale 'dclone' pour ce cas –

29

De la documentation Storable :: dclone J'ai trouvé Clone:

my $copy = clone (\@array); 

# or 

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

Ne pas besoin de flexibilité et prétend être plus rapide que Storable::dclone.

+2

Benchmark montre que c'est environ deux fois plus vite que dclone – Oesor

+0

ressemble à ceci ne pas cloner threads :: structure de données partagées? Impossible de trouver la méthode d'objet "FETCH" via le paquet "threads :: shared :: tie" – ealeon

7

structure de données profonde 101:

  • utilisation de dcloneStorable pour faire une copie en profondeur d'une structure et freeze et thaw à linéariser/désérialiser les pour le stockage (par exemple dans une base de données, ou cookie http (mais vous devriez crypter tout ce que vous envoyez à l'utilisateur pour le rendre plus difficile à manipuler).
  • Utilisez Data::Compare (ou Test::Deep ou Test::Differences dans un test unitaire) pour comparer deux structures de données profondes.
  • Utilisez Data::Dumper ou Data::Dump dans le débogage pour voir à quoi ressemblent vos objets. Mais ne l'utilisez pas comme une licence pour altérer les composants internes d'un autre objet; utilisez l'API. :)
+1

Data :: Comparer est nouveau pour moi aussi, je viens de me détendre mes hashes pour les vérifier. Je vais être sûr de l'essayer un certain temps pour comparer des choses vraiment compliquées; merci – Oesor

+1

Test :: Deep, et Test :: Les différences tombent en disgrâce en raison de l'omniprésente Test :: More is_deeply nouvelle fonctionnalité - vérifier. Dirt simple à utiliser, et vous obtenez une jolie erreur. –

Questions connexes