http://www.perlmonks.org?node_id=819159

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

Dear Monks,

Suppose you have two parallel arrays:

my @keys = qw {red blue red}; my @vals = (1, 2, 3);

Does perl have an idiom to end up with this:

my %hash = ( red => [1, 3], blue => [2], )

That is, does perl have an idiom for: create a key if it doesn't exist and assign it a default empty array then push the current integer onto the array; else if the key already exists push the current integer onto its corresponding array?

Replies are listed 'Best First'.
Re: idiom for building hash of arrays?
by CountZero (Bishop) on Jan 23, 2010 at 12:07 UTC
    This works:
    use strict; use warnings; use List::MoreUtils qw/zip natatime/; use Data::Dump qw/dump/; my @keys = qw {red blue red}; my @vals = (1, 2, 3); my %hash; my $it = natatime 2, zip @keys, @vals; while (my ($key, $value) = $it->()) { push @{$hash{$key}}, $value; } print dump(\%hash);
    The idiom you are looking for is
    push @{$hash{$key}}, $value;

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: idiom for building hash of arrays?
by FunkyMonk (Chancellor) on Jan 23, 2010 at 12:29 UTC
    If you don't need @vals after you've built the hash, this will build your hash without using any modules:
    use Data::Dump 'pp'; # a nicer Data::Dumper my @keys = qw {red blue red}; my @vals = (1, 2, 3); my %hash; push @{$hash{$_}}, shift @vals for @keys; pp \%hash; __END__ { blue => [2], red => [1, 3] }

    If you do need @vals, you could replace the above loop with:

    push @{$hash{$keys[$_]}}, $vals[$_] for 0..$#keys;

    Update: Re-added the call to pp


    Unless I state otherwise, all my code runs with strict and warnings
Re: idiom for building hash of arrays?
by ww (Archbishop) on Jan 23, 2010 at 12:02 UTC
Re: idiom for building hash of arrays?
by Anonymous Monk on Jan 23, 2010 at 15:32 UTC
    push @{ $hash{$key} //= [] }, $current;

    (For perl versions < 5.10, ||= is functionally the same in this case because the hash value is always a reference, which is false iff it is undefined.)

Re: idiom for building hash of arrays?
by Anonymous Monk on Jan 23, 2010 at 11:10 UTC
    Here is an idea, come up with an algorithm, write code with it, and I'll tell you if its idiomatic :)
      ||= []