http://www.perlmonks.org?node_id=612615

merge one hash into another using a hash slice. Note that the new values replace any previous values with the same key.
@target{keys %source} = values %source;

Replies are listed 'Best First'.
Re: Merge hash into another hash
by ides (Deacon) on Apr 29, 2007 at 15:19 UTC

    That works great for simple hashes, but if you have a complex data structure you'll definitely want to check out Hash::Merge

    Frank Wiles <frank@revsys.com>
    www.revsys.com

      This is what I would definitely use for complex structure, as I would have different rules for certain keys at different depth levels.

      As for simple merge, I tend to use the opposite of what GrandFather uses. My target hashes are mostly new initialized ones, and the the source is taken as custom values that override the default. So I just stuff source into target. Because the source hash is actually a reference, it will be dereferenced.

      sub some_meth { my($self, $source) = @_; my %target = ( key1 => 'default_1', key2 => 'default_2', keyN => 'default_N', %$source, ); # do somethings with %target }
      Of course, GrandFather's technique can be applied as well. And I can see an advantage to have a chance to check the source prior to merging.
      my %target = ( # initialization ); %target{keys %$source} = values %$source if defined $source && ref $source eq 'HASH';

      Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

        For simple hashes, what's wrong with just:

        my %target = ( #initialize ); %target = (%target, %source)
        ? (with the issues of complex cases, source checking, and dereferencing aside (but perhaps fixable))

        jason.

Re: Merge hash into another hash
by ruzam (Curate) on Nov 18, 2009 at 23:54 UTC

    Unless I'm mistaken, both 'keys' and 'values' will make Perl gather up all the elements of each into temporary lists before even attempting to assign them. If %source is really huge, then that could be a problem?

    If I thought memory use was a concern I'd walk the key values instead.

    while (my($key, $value) = each %source) { $target{$key} = $value }

    But I imagine Perl is pretty good at handling temporary lists, so I doubt looping through the keys would be as fast.

    Update

    ... and just for fun

    Update Again (used the wrong target in the benchmark)

    cmpthese( -1, { grandfather => sub { my %t = %target; @t{keys %source} = values %source; }, sleepyjay => sub { my %t = %target; %t = ( %t, %source ); }, ruzam => sub { my %t = %target; while ( my($key, $value) = each %source) { # $target{$key} = $value <-- oops! $t{$key} = $value } }, }); __END__ Rate sleepyjay ruzam grandfather sleepyjay 905/s -- -58% -61% ruzam 2162/s 139% -- -8% grandfather 2349/s 160% 9% --
Re: Merge hash into another hash
by eamallove (Initiate) on Nov 18, 2009 at 19:54 UTC
    To preserve the key->{value} structure of the hash, I had to create a recursive function. This works for me:
    sub merge_hashes { my ($x, $y) = @_; foreach my $k (keys %$y) { if (!defined($x->{$k})) { $x->{$k} = $y->{$k}; } else { $x->{$k} = merge_hashes($x->{$k}, $y->{$k}); } } return $x; }