问题
Possible Duplicate:
What's the best way to make a deep copy of a data structure in Perl?
Before I start coding this myself and reinventing the wheel, how do you copy a hash of hashes without duplicating the hashrefs?
I'm reading a hash of hash of hashes via Config::General. i.e., the data structure is:
my %config = ( group => { item1 => { foo => 'value',
bar => 'value',
},
item2 => { foo => 'value',
bar => 'value',
},
item3 => { foo => 'value',
bar => 'value',
},
},
);
I then pull my group from the config by dereferencing it and change the contents at runtime prior to rewriting the config file:
my %group = %{$config{'group'}};
The problem is that I need to check to see if changes were made and make associated changes to the system's file structure. I can't do this by checking:
if ($group{'item1'}{'foo'} ne $config{'group'}{'item1'}{'foo'}) {
### Stuff!
}
as $group{'item1'} and $config{'group'}{'item1'} are both the exact same hashref.
Now while it should be trivial to simply re-parse the config file, and compare the parsed copy from the disk against the edited version just before saving to disk, I'm sure there's a way to to a nested dereference of a complex data structure, copying the contents of the hash refs and not simply copying the references themselves. A cursory examination on CPAN doesn't turn anything up. What am I missing?
Benchmark
Got my answer:
#!/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 }},
});
results 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)
回答1:
use Storable qw(dclone);
$group2 = dclone(\%group);
回答2:
From the Storable::dclone documentation I found Clone:
my $copy = clone (\@array);
# or
my %copy = %{ clone (\%hash) };
Don't need flexibility, and claims to be faster than Storable::dclone.
回答3:
Deep data structure 101:
- Use Storable's
dcloneto make a deep copy of a structure, andfreezeandthawto serialize/deserialize them for storage (say in a database, or an http cookie (but you should encrypt anything you send to the user to make it harder to tamper with). - Use Data::Compare (or Test::Deep or Test::Differences inside a unit test) to compare two deep data structures.
- Use Data::Dumper or Data::Dump in debugging to see what your objects look like. But don't use that as a licence to tamper with another object's internals; use the API. :)
回答4:
Could always store the hash via Storable or Data::Dumper, and reassigned the stored value into a new hash. This should get a full copy without maintaining the referenced links.
use Storable;
my $serialized = freeze \%config;
my %newconfig = %{ thaw($serialized) };
来源:https://stackoverflow.com/questions/1546322/whats-the-best-way-to-deep-copy-a-hash-of-hashes-in-perl