Question

There is a question that explains exactly what I want here: how to merge 2 deep hashes in perl

However, the answer there does not seem to work for me (suggestions of using the Merge module).

I have two hashes like so:

$VAR1 = {
          '57494' => {
                       'name' => 'John Smith',
                       'age' => '9',
                       'height' => '120'
                     },
          '57495' => {
                       'name' => 'Amy Pond',
                       'age' => '17',
                       'height' => '168'
                     }
        }
};
$VAR1 = {
          '57494' => {
                       'name_address' => 'Peter Smith',
                       'address' => '5 Cambridge Road',
                       'post_code' => 'CR5 0FS'
                     }
        }
};

If I use Hash::Merge or the %c = {%a,%b} format I get this every time:

$VAR1 = '57494';
$VAR2 = {
          'name_address' => 'Peter Smith',
          'address' => '5 Cambridge Road',
          'post_code' => 'CR5 0FS'
        };

(so it basically overwrote the first data with the second and messed up the keys) when I want:

$VAR1 = {
          '57494' => {
                       'name' => 'John Smith',
                       'age' => '9',
                       'height' => '120'
                       'name_address' => 'Peter Smith',
                       'address' => '5 Cambridge Road',
                       'post_code' => 'CR5 0FS'
                     },
          '57495' => {
                       'name' => 'Amy Pond',
                       'age' => '17',
                       'height' => '168'
                     }
        }
};

So when the keys are the same, the data merges together, otherwise the new keys are just appended onto the end. I hope this make sense. Maybe I've done something incorrectly using Merge or need to 'manually' add them in loops, but I'm spending too much time thinking about it, regardless!

Edit: how I use Merge to see if I'm doing something silly:

I have:

use Hash::Merge qw( merge );

...hash data above as %hash1 and %hash2...

my %combined_hash = %{ merge( %hash1,%hash2 ) };
print Dumper(%combined_hash);
Was it helpful?

Solution

If I do it with references, it works like a charm.

use strict; use warnings;
use Data::Dumper;
use Hash::Merge qw(merge);
my $h1 = {
  '57494' => {
    'name'   => 'John Smith',
    'age'    => '9',
    'height' => '120'
  },
  '57495' => {
    'name'   => 'Amy Pond',
    'age'    => '17',
    'height' => '168'
  }
};

my $h2 = {
  '57494' => {
    'name_address' => 'Peter Smith',
    'address'      => '5 Cambridge Road',
    'post_code'    => 'CR5 0FS'
  }
};

my $h3 = merge( $h1, $h2 );
print Dumper $h3;

Output:

$VAR1 = {
      '57495' => {
                   'name' => 'Amy Pond',
                   'age' => '17',
                   'height' => '168'
                 },
      '57494' => {
                   'name_address' => 'Peter Smith',
                   'name' => 'John Smith',
                   'post_code' => 'CR5 0FS',
                   'address' => '5 Cambridge Road',
                   'height' => '120',
                   'age' => '9'
                 }
    };

If, however, I do it with hashes instead of hash refs, it doesn't:

my %hash1 = (
  '57494' => {
    'name'   => 'John Smith',
    'age'    => '9',
    'height' => '120'
  },
  '57495' => {
    'name'   => 'Amy Pond',
    'age'    => '17',
    'height' => '168'
  }
);

my %hash2 = (
  '57494' => {
    'name_address' => 'Peter Smith',
    'address'      => '5 Cambridge Road',
    'post_code'    => 'CR5 0FS'
  }
);

my %h3 = merge( %hash1, %hash2 );
print Dumper \%h3;

__END__
$VAR1 = {
  '57495' => undef
};

That is because the merge from Hash::Merge can only take references, but you are passing it hashes. In addition, you need to call it in scalar context.

Try it like so:

#                             +--------+--- references
#   ,-- SCALAR context        |        |
my $combined_hash = %{ merge( \%hash1, \%hash2 ) };
print Dumper($combined_hash);

OTHER TIPS

for my $key (keys %fromhash) {
    if(not exists $tohash{$key}) {
        $tohash{$key} = {};
    }
    for my $subkey (keys %{$fromhash{$key}}) {
        ${$tohash{$key}}{$subkey} = ${$fromhash{$key}}{$subkey};
    }
}

With more or less braces depending on whether my last coffee was any good.

Python is definitely more comfortable for this kind of thing, because it doesn't make you think about references:

for key in fromdict:
    if key not in todict:
        todict[key] = {}
    todict[key] = dict(fromdict[key].items() + todict[key].items())

Or if todict is a defaultdict (creating keys on read as well as assignment):

for key in fromdict:
    todict[key] = dict(dict(fromdict[key]).items() + dict(todict[key]).items())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top