Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

How to combine two different hashes into single hash.

by Sami_R (Sexton)
on Dec 28, 2019 at 22:51 UTC ( [id://11110710]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks,

Have two hashes, need to combine two hashes into single hash.

my $VAR1 = { 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 } }; my $VAR2 = { 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 }, 'Adam' => { 'jkl' => 7, 'mno' => 0, 'pqr' => 7 } };

Expected output:

my $VAR3 = { 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0, 'jkl' => 7, 'mno' => 0, 'pqr' => 7 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 } };

Monks, please explain me how to achieve this. Thanks in advanced

Replies are listed 'Best First'.
Re: How to combine two different hashes into single hash.
by LanX (Saint) on Dec 28, 2019 at 23:17 UTC
    > need to combine two hashes into single hash.

    nope, you have a hash of hashes and want to join the second layer hashes with the same first layer keys.

    joining hashes is easy %join = (%h1,%h2) (NB: it will eliminate duplicate keys from %h1 though).

    what you need is to find the set of all 1st-keys to join the second layer hashes

    use strict; use warnings; use Data::Dump qw/pp dd/; my %h1 = ( 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 } ); my %h2 = ( 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 }, 'Adam' => { 'jkl' => 7, 'mno' => 0, 'pqr' => 7 } ); my %joined_1st = (%h1,%h2); #pp \%joined_1st; my %joined_2nd = map { $_ => { %{ $h1{$_} // {} }, %{ $h2{$_} // {} } } } keys %joined_1st; pp \%joined_2nd;

    { Adam => { abc => 0, def => 0, ghi => 0, jkl => 7, mno => 0, pqr => 7 + }, Dav => { jkl => 12, mno => 34, pqr => 45 }, keas => { abc => 0, def => 0, ghi => 0 }, Tim => { abc => 7, def => 7, ghi => 0 }, }
    Questions?

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      Thanks Rolf,

      Firstly, I should convert hash of hashes into hash and then use join ?

      my $VAR1 = {'Tim' => {'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => +{ 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' + => 0, 'ghi' => 0 }}; my %h1 = ('Tim' => {'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { +'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' = +> 0, 'ghi' => 0 });

      Apologies if I wrongly understood.

        I couldn't tell if your input and output hashes are in form of references or not.

        The following is a variant for references:

        use strict; use warnings; use Data::Dump qw/pp dd/; my $h1 = { 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 } }; my $h2 = { 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 }, 'Adam' => { 'jkl' => 7, 'mno' => 0, 'pqr' => 7 } }; my %joined_1st = (%$h1,%$h2); #pp \%joined_1st; my $joined_2nd = { map { $_ => { %{ $h1->{$_} // {} }, %{ $h2->{$_} // {} } } } keys %joined_1st }; pp $joined_2nd;

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: How to combine two different hashes into single hash.
by tobyink (Canon) on Dec 28, 2019 at 23:17 UTC

    my $VAR1 = { 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 } }; my $VAR2 = { 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 }, 'Adam' => { 'jkl' => 7, 'mno' => 0, 'pqr' => 7 } }; my %output; $output{$_} ||= {( %{$VAR1->{$_}}, %{$VAR2->{$_}} )} for keys(%$VAR1), keys(%$VAR2); use Data::Dumper; print Dumper \%output;

    I'll explain how this all works.

    for keys(%$VAR1), keys(%$VAR2) will loop through the keys of both hashes. Some keys are in both arrays, so they'll be visited on the loop twice, but we can worry about that later. The key is in the variable $_.

    %{$VAR1->{$_}} and %{$VAR2->{$_}} get the nested hashes from $VAR1 and $VAR2 using the key $_

    (... , ...) combines those two hashes into a single list of key-value pairs. And wrapping that in { ... } creates a new hash using those key-value pairs and returns a reference to it.

    $output{$_} is the slot in the new hash %output to store the hashref created above, and assigning to it with ||= will skip all of the above stuff if $output{$_} is already true. (This skips duplicated keys. Though duplicated keys aren't actually a problem in this case; they would merely slow down the loop an almost immeasurably small amount.)

      Running your code I get "Can't use an undefined value as a HASH reference" (update: using warnings )

      ... and Perl exits "compilation exited abnormally with code 255 at Sun Dec 29 00:36:58" (update: using strict )

      That's why I had to add the // {} parts in my code to default to an empty hash.

      Did you tweak your Perl?

      my version: This is perl 5, version 24, subversion 1 (v5.24.1) built for MSWin32-x64-multi-thread

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        It'll do that with use strict.

        You could do this:

        my %output; $output{$_} ||= {( %{$VAR1->{$_}||{}}, %{$VAR2->{$_}||{}} )} for keys(%$VAR1), keys(%$VAR2);

        Not really any need to use the // operator which limits backwards compatibility. (Introduced in Perl 5.10.)

      Thanks Toby, Great detailed explanation.
Re: How to combine two different hashes into single hash.
by 1nickt (Canon) on Dec 29, 2019 at 00:19 UTC

    Hash::Merge

    use strict; use warnings; use feature 'say'; use Data::Dumper; $Data::Dumper::Sortkeys = 1; $Data::Dumper::Indent = 1; use Hash::Merge 'merge'; my $VAR1 = { 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 } }; my $VAR2 = { 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 }, 'Adam' => { 'jkl' => 7, 'mno' => 0, 'pqr' => 7 } }; my $output = merge($VAR1, $VAR2); say Dumper $output;
    Output:
    $VAR1 = { 'Adam' => { 'abc' => 0, 'def' => 0, 'ghi' => 0, 'jkl' => 7, 'mno' => 0, 'pqr' => 7 }, 'Dav' => { 'jkl' => 12, 'mno' => 34, 'pqr' => 45 }, 'Tim' => { 'abc' => 7, 'def' => 7, 'ghi' => 0 }, 'keas' => { 'abc' => 0, 'def' => 0, 'ghi' => 0 } };

    Hope this helps!


    The way forward always starts with a minimal test.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11110710]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-18 18:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found