http://qs321.pair.com?node_id=531794

jkva has asked for the wisdom of the Perl Monks concerning the following question:

Esteemed Monks.

Let's say I have two hashes :
%hash1 = ( foo => 'bar', baz => { quux => 'qwe', rty => 'uiop', }, perl => ['monks', 'monastery', 'robes'], ) %hash2 = ( wizardry => 'hocus-pocus', foo => 'f00', baz => { grail => 'arthur', }, perl => ['yayy', 'yippee'], hash3 => {key1 => 'value1', key2 => 'value2', }, );

I'd like to "add" %hash2 to %hash1, and existing data should be overwritten while nonexistent data should be added. What would be the best approach to this?

-- jkva

Replies are listed 'Best First'.
Re: Combining / Merging two Ho(H|A)s
by GrandFather (Saint) on Feb 21, 2006 at 21:02 UTC

    You could try something recursive like this:

    use warnings; use strict; use Data::Dump::Streamer; my %hash1 = ( foo => 'bar', baz => { quux => 'qwe', rty => 'uiop', }, perl => ['monks', 'monastery', 'robes'], ); my %hash2 = ( wizardry => 'hocus-pocus', foo => 'f00', baz => { grail => 'arthur', }, perl => ['yayy', 'yippee'], hash3 => {key1 => 'value1', key2 => 'value2', }, ); merge (\%hash2, \%hash1); Dump (\%hash1); sub merge { my ($source, $target) = @_; for (keys %$source) { if ('ARRAY' eq ref $target->{$_}) { push @{$target->{$_}}, @{$source->{$_}}; } elsif ('HASH' eq ref $target->{$_}) { merge ($source->{$_}, $target->{$_}); } else { $target->{$_} = $source->{$_}; } } }

    DWIM is Perl's answer to Gödel
Re: Combining / Merging two Ho(H|A)s
by Roy Johnson (Monsignor) on Feb 21, 2006 at 21:35 UTC
    Have a look at Hash::Merge.

    Caution: Contents may have been coded under pressure.
Re: Combining / Merging two Ho(H|A)s
by jdporter (Paladin) on Feb 21, 2006 at 23:22 UTC

    You didn't say what should happen when there are existing values in the two hashes, but their types are different. For example,

    %h1 = ( foo => 1, ); %h2 = ( foo => { bar => 2, }, );
    Do you have reason to believe this won't happen?

    We're building the house of the future together.
      Very very good point. It is possible. I'd say the first hash's value should be overwritten by the second one.
      GrandFather's code can be easily changed to check for REF differences and act accordingly.

        Right; but I would definitely look into Hash::Merge (Roy_Johnson's suggestion).

        We're building the house of the future together.
Re: Combining / Merging two Ho(H|A)s
by ikegami (Patriarch) on Feb 21, 2006 at 21:14 UTC
    When dealing with data structures and you want something to occur at all levels, it is said to occur "in depth" or "deeply", or is said to be "deep". GrandFather's solution merges deeply, while xorl and Corion's solution merge shallowly.
Re: Combining / Merging two Ho(H|A)s
by Corion (Patriarch) on Feb 21, 2006 at 21:02 UTC

    If you just want the data to be overwritten, it's easy and no loop is needed when you use a hash slice:

    @hash1{ keys %hash2 } = values %hash2;

    Oh - now I see that you wanted this done recursively. Then you'll need something like GrandFather wrote

Re: Combining / Merging two Ho(H|A)s
by xorl (Deacon) on Feb 21, 2006 at 20:59 UTC
    There's nothing like the brute force method
    foreach my $key2 (keys %hash2) { $hash1{$key2} = $hash2{$key2}; }
    Code untested and probably not has elegant as it could be.
      Brute it is. Perhaps I didn't specify that well enough - in this case the nested hashes overwrite eachother instead of merging. This is not what I intend.
      Thanks for your reply, though.