Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Merging hashes

by hotshot (Prior)
on Sep 10, 2002 at 11:51 UTC ( #196629=perlquestion: print w/replies, xml ) Need Help??
hotshot has asked for the wisdom of the Perl Monks concerning the following question:

hi fellers !

how can I merge several hashes to one. suppose I have the following hashes:
%hash1 = ( red => 1, brown => ( green => 1, blue => ( yellow => 1, ), black => 1, ), gray => 1, ); %hash2 = ( white => 1, brown => ( purple => 1, ), );
I want to get in the end the following hash:
%mergedHash = ( red => 1, gray => 1, white => 1, brown => ( green => 1, purple => 1, black => 1, blue => ( yellow => 1, ), ), );
another thing, how can I do this if I have references of hashes (replace the brackets with curly ones in the example above)?

Thanks

Hotshot

Replies are listed 'Best First'.
Re: Merging hashes
by valdez (Monsignor) on Sep 10, 2002 at 12:50 UTC

    Have you tried with Hash::Merge? This module can merge arbitrarily deep hashes into a single hash; it can also merge ARRAYs and SCALARs. Hope this helps.

    Ciao, Valerio

Re: Merging hashes
by kabel (Chaplain) on Sep 10, 2002 at 12:07 UTC
    in fact those need to be references due to list flattening. your %hash1 is not built as you want (same for %hash2). you can see this by just printing out your data structures and try to guess what happens:
    use strict; use Data::Dumper; my %hash1; # fill %hash1 here print Dumper \%hash1;
      Got it, in fact I use references (it's my question that wasn't clear enough), the thing is that I always stay with one value for the same keys, if I'll take my example from the question, then I get only one brown entry. The references always clober each other and not added, I didn't seem to solve that yet.

      Hotshot
        Thats what hashes do. map a unique key to a unique values. But you can make that value an array ref and store your multiple values.

        It also looks like you want to apply it recursively. May I ask what you are trying to do?

        -Lee

        "To be civilized is to deny one's nature."
        UPDATE
        Here's enough rope to hang yourself with.
        Merges N hashes arbitrarily deep. Making it merge arrays as well is left as an exercise for the reader.
        Dies on circular references. Not heavily tested.
        #!/usr/bin/perl use warnings; use strict; use Data::Dumper; BEGIN { my %SeenMerged = (); sub mergehashes{ # Dies on circular references my @hashrefs = @_; die "Passed a non hashref" if grep { ref $_ ne 'HASH' } @h +ashrefs; my %merged = (); my @seen = grep { ref $_ eq 'HASH' } @SeenMerged{@hashref +s}; # Break circular links.. if (@seen){ die "contains a circular reference! bailing..."; } @SeenMerged{@hashrefs} = @hashrefs; foreach my $h (@hashrefs){ while (my ($k,$v) = each %$h ){ push @{$merged{$k}}, $v; } } while (my ($k,$v) = each %merged){ my @hashes = grep { ref $_ eq 'HASH' } @$v; $merged{$k} = $v->[0] if (@$v == 1 && !ref $v->[0]); + $merged{$k} = mergehashes(@hashes) if @hashes; } delete @SeenMerged{@hashrefs}; return \%merged; } } my %hash1 = ( red => 1, brown => { green => 1, blue => { yellow => 1, }, black => 1, }, gray => 1, ); my %hash2 = ( white => 1, brown => { purple => 1, }, ); my $merged = mergehashes(\%hash1, \%hash2) ;#or die "Couldn't merge!"; print Dumper($merged);
Re: Merging hashes
by abell (Chaplain) on Sep 10, 2002 at 13:02 UTC
    This does it:
    #!/usr/bin/perl -w use Data::Dumper; %hash1 = ( red => 1, brown => { green => 1, blue => { yellow => 1, }, black => 1, }, gray => 1, ); %hash2 = ( white => 1, brown => { purple => 1, }, ); # merge ( \%hash1, \%hash2 ) returns the merge # If the two hashes have a common (possibly deep) key # not pointing to hashes, it dies trying to force # the reference to a hash reference sub merge { my ( $h1, $h2 ) = @_; my %h3; for my $key ( keys %$h1 ) { if ( exists $h2->{$key} ) { $h3{$key} = merge( $h1->{$key}, $h2->{$key} ); } else { $h3{$key} = $h1->{$key}; } } for my $key ( keys %$h2 ) { unless ( exists $h1->{$key} ) { $h3{$key} = $h2->{$key}; } } return \%h3; } print Dumper ( merge( \%hash1, \%hash2 ) );

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://196629]
Approved by davis
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2018-07-20 16:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?















    Results (438 votes). Check out past polls.

    Notices?