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
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?
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] |
|
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;
| [reply] [d/l] |
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.)
| [reply] [d/l] [select] |
|
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
| [reply] [d/l] [select] |
|
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.)
| [reply] [d/l] [select] |
|
Thanks Toby,
Great detailed explanation.
| [reply] |
Re: How to combine two different hashes into single hash.
by 1nickt (Canon) on Dec 29, 2019 at 00:19 UTC
|
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.
| [reply] [d/l] [select] |
|
|