Reputation: 21450
I write a sub in Perl to merge 2 hashes of the same structure; so that merge($a,$b)
$a = {
k1 => { sk1 => 'v1' },
k2 => { sk3 => 'v3', sk4 => 'v4' }
};
$b = {
k1 => { sk2 => 'v2'},
k3 => { sk5 => 'v5'}
};
would result in
$c = {
k1 => { sk1 => 'v1', sk2 => 'v2' },
k2 => { sk3 => 'v3', sk4 => 'v4' }
k3 => { sk5 => 'v5'}
};
Below is my code for merge, and it does not work. How can I correct it? Thank you.
sub merge {
my ($old,$new) = @_;
foreach my $k (keys($old)) {
if (exists $new->{$k}) {
if (ref($old->{$k}) eq 'HASH') {
merge($old->{$k},$new->{$k});
} else {
$new->{$k} = $old->{$k};
}
} else {
$new->{$k} = $old->{$k};
}
}
return $new;
}
Upvotes: 4
Views: 4404
Reputation: 80423
This should be plenty good enough:
for my $href ($a, $b) {
while (my($k,$v) = each %$href) {
$c->{$k} = $v;
}
}
If you don't want to clobber duplicates, perhaps because you're concerned about ordering issues, instead use:
for my $href ($a, $b) {
while (my($k,$v) = each %$href) {
push @{ $c->{$k} }, $v;
}
}
The advantage of doing this very simple operation yourself is it helps develop facility with basic Perl data structures, something critical on the path to fluency in the language.
Note however that these are surface copies, so references will be shared. It's not a deep copy.
I used each
instead of keys
so that it scales in case you use DBM hashes with millions of elements.
Upvotes: 2
Reputation: 27886
Unless you're doing this just to learn how it's done, I'd use a premade solution like Hash::Merge or Hash::Merge::Simple.
Upvotes: 11