Re: merge two hashes into one
by choroba (Cardinal) on May 29, 2018 at 19:05 UTC
|
Initialise the new hash with one of the old ones, so you can only iterate over the other one:
#!/usr/bin/perl
use warnings;
use strict;
my %hash1 = (a => 12, b => 15);
my %hash2 = (a => 30, c => 17);
my %merged = %hash1;
$merged{$_} += $hash2{$_} for keys %hash2;
use Data::Dumper;
print Dumper \%merged;
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
Re: merge two hashes into one
by hippo (Archbishop) on May 29, 2018 at 17:49 UTC
|
| [reply] |
Re: merge two hashes into one
by AnomalousMonk (Archbishop) on May 29, 2018 at 17:12 UTC
|
c:\@Work\Perl>perl -wMstrict -MData::Dump -le
"my %h1 = qw(foo 3 bar 99);
my %h2 = qw(foo 5 bar 87);
;;
die 'hashes unequal: merging invalid' if keys %h1 != keys %h2;
;;
for my $k (keys %h1) {
die qq{key '$k' not found: merging invalid} unless exists $h2{$k};
$h1{$k} += $h2{$k}
}
;;
dd \%h1;
"
{ bar => 186, foo => 8 }
Update: Hey, isn't this a FAQ somewhere? Can't find it ATM.
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: merge two hashes into one
by stevieb (Canon) on May 29, 2018 at 17:19 UTC
|
map is useful here. The following example assumes that keys in both hashes are the same; ie. %h2 does not have any extra keys that %h1 doesn't have.
use strict;
use Data::Dumper;
my %h1 = (a => 1, b => 2, c => 3);
my %h2 = (a => 6, b => 8, c => 0);
my %h3 = map {$_ => $h1{$_} + $h2{$_}} keys %h1;
print Dumper \%h3;
Output:
$VAR1 = {
'c' => 3,
'b' => 10,
'a' => 7
};
If %h2 does have keys that %h1 doesn't have, change this line:
my %h3 = map {$_ => $h1{$_} + $h2{$_}} keys %h1;
...to this:
my %h3 = map {$_ => $h1{$_} + $h2{$_}} keys %h1, keys %h2;
| [reply] [d/l] [select] |
|
|
c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le
"my %h1 = qw(a 1 b 2 c 3 );
my %h2 = qw( b 7 c 8 d 4);
;;
my %h_out =
map exists $h2{$_} ? ($_ => $h1{$_} + $h2{$_}) : (),
keys %h1
;
dd \%h_out;
"
{ b => 9, c => 11 }
The exists test could be moved into a separate grep step for perhaps greater clarity, but I'd expect a bit of a performance hit with large hashes.
BTW: Won't
my %h3 = map {$_ => $h1{$_} + $h2{$_}} keys %h1, keys %h2;
cause "Use of uninitialized value ..." warnings unless that warning is disabled?
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
my %h1 = qw( a 1 b 2 c 3 );
my %h2 = qw( b 7 c 8 d 4 );
my %h3 = map { $_ => $h1{$_} // 0 + $h2{$_} // 0 } keys %h1, keys %h2;
No warnings, merges both hashes
Enjoy, Have FUN! H.Merijn
| [reply] [d/l] |
|
|
Re: merge two hashes into one
by jdporter (Paladin) on May 30, 2018 at 17:06 UTC
|
My solution, designed to take any number of hashes, not just two. Encapsulated in a function named add_hashes. Uses some functions in List::Util.
use List::Util qw( sum uniq );
# pass list of hashrefs.
# returns a hash (list).
sub add_hashes(@)
{
map { my $k = $_; $k =>
sum( map $_->{$k}, @_ ) }
uniq( map keys(%$_), @_ )
}
Test it:
my %h1 = map { ( $_ => 1 ) } qw( a b c d e f g h );
my %h2 = map { ( $_ => 1 ) } qw( b c d e f g h i );
my %h3 = map { ( $_ => 1 ) } qw( c d e f g h i j );
my %h4 = map { ( $_ => 1 ) } qw( d e f g h i j k );
my %summed = add_hashes(
\%h1,
\%h2,
\%h3,
\%h4,
);
use Data::Dumper;
$Data::Dumper::Sortkeys=1;
print Dumper \%summed;
| [reply] [d/l] [select] |
Re: merge two hashes into one
by Veltro (Hermit) on May 29, 2018 at 20:02 UTC
|
use strict ;
use warnings ;
use Data::Dumper ;
my $h1 = { a => 1, b => 2 } ;
my $h2 = { a => 1, c => 3 } ;
foreach( keys %{ $h2 } ) {
merge( $h1 )->( $_ ) += $h2->{ $_ } ;
}
print Dumper( $h1 ) ;
sub merge : lvalue {
my $inh = $_[0] ;
my $ret = sub : lvalue {
$inh->{ $_[0] } ;
} ;
$ret ;
}
| [reply] [d/l] |
Re: merge two hashes into one
by AnomalousMonk (Archbishop) on May 30, 2018 at 01:30 UTC
|
| [reply] [d/l] |
Re: merge two hashes into one
by Anonymous Monk on May 30, 2018 at 19:46 UTC
|
use List::Util qw( reduce pairs );
# Firm talk so perl know I mean it.
reduce ## abuce
{ $$a {
$$b[0]
} += $$b[1],$a } \
# It simple now.
my %result => pairs %h1, %h2, %h3, %h4;
| [reply] [d/l] |
Re: merge two hashes into one
by locked_user sundialsvc4 (Abbot) on May 29, 2018 at 22:20 UTC
|
Some of the offered answers seem wrong to me. If you want to add an element to the output hash only if the key exists in both inputs, I think that you would need something that is essentially this (tested) logic:
use strict; use warnings;
use Data::Dumper;
my $h1 = { 'a' => 1, 'b' => 2, 'c' => 3 };
my $h2 = { 'b' => 2, 'c' => 4, 'd' => 5 };
my $hout = {};
foreach my $k (keys $h1) {
if (exists $h2->{$k}) {
$hout->{$k} = $h1->{$k} + $h2->{$k};
}
}
print Data::Dumper->Dump([$hout], ['hout']);
$hout = {
'b' => 4,
'c' => 7
};
Loop through all of the keys in one hash and check to see if this key also exists in the other. If so, populate the output hash with the sum of the two.
Looking through the various answers, it seemed to me that some either modified $h1, or assumed that the key existed in $h2, or relied upon side effects. (Of course I did not down-vote any of them – I never do – and perhaps I am quite mistaken.)
Now, as far as “a good-looking, less-coded way,” the only criteria that really matters to me is that the logic is tested, that it is “at-a-glance obvious to anyone and everyone,” and that it is easy to maintain. If a future program-change requirement is to do different or additional things to the matching elements, it should be easy to make that modification without breaking what’s there. I place no premium on brevity – quite the opposite. (My career experience commonly deals with software that is dozens of years old and built by a great many someone-elses, so I am very keen to such concerns.)
| |
|
|
| [reply] |
|
|
So when you "tested" this ... you saw the "keys on reference is experimental" warning .... Otherwise your code didn't compile at all ...
I don't know what Perl version sundialsvc4 was using, but I tested the code under Perl 5.14 and it works as advertised.
I and many others have long had a problem with sundialsvc4: he so often just doesn't seem to know what the hell he's talking about. Even when I occasionally encounter a post of his that seems, at first glance, to make a valid point, I have gotten into the habit of simply passing on by: I've been bitten too often by bugs and gotchas that only become apparent on closer inspection or through the replies of others to risk upvoting.
Lately, I've seen a couple of his posts that are so clear, straighforward and helpful that I've upvoted them; this is one. Of course, a note about the "highly experimental" nature of keys EXPR would have been nice and there's still a bit of bloviation, but you can't have everything. There's code, compilable, runnable code that works as described, and a few valid points! sundialsvc4 takes up so much bandwidth on this site that it's a shame his contributions haven't been correspondingly worthwhile. Is a new day dawning? I hope so, and I think any effort in that direction is worth encouraging.
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
|
|
|
|