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

Hi, I am not sure how to call this but I need to group some data from an array of hashes. They keys are not unique and I'd like to group all the keys and print all the values on one line. Here is the array of hashes and I show what I'd like to see at the bottom. Could anyone give me some hints how to do this? thanks, benny
push @all_queries,{'foo' => 20}; push @all_queries,{'bar' => 30}; push @all_queries,{'foo' => 10}; push @all_queries,{'zen' => 90}; push @all_queries,{'zen' => 1};
I'd like to display the output like below
bar has 30 foo has 10,20 zen has 1,90

Replies are listed 'Best First'.
Re: 'group by query' from array of hashes
by ikegami (Patriarch) on Jan 28, 2011 at 23:04 UTC

    The tricky part is that the hash's key is variable. You need to not only extract the value, but the key. Once you do that, simply build the desired HoA.

    my %grouped; for (@queries) { my ($k,$v) = %$_; push @{ $grouped{$k} }, $v; }

    The array will automatically get vivified by the lvalue «@{ }» as if you did «$grouped{$k} //= [];», saving you the trouble.

Re: 'group by query' from array of hashes
by wind (Priest) on Jan 28, 2011 at 22:19 UTC
    my @all_queries = ( {'foo' => 20}, {'bar' => 30}, {'foo' => 10}, {'zen' => 90}, {'zen' => 1}, ); my %hash; push @{$hash{(keys %$_)[0]}}, (values %$_)[0] foreach (@all_queries); foreach my $key (keys %hash) { print "$key has " . join(',', @{$hash{$key}}) . "\n"; }
    - Miller
Re: 'group by query' from array of hashes
by chayashida (Acolyte) on Jan 29, 2011 at 03:26 UTC

    I think you need to use the syntax that forces types to arrays and hashes. It's in the Hashes of Arrays section of Chapter 9, Data Structures in the Camel book.

    my %queries_by_key = (); # Hash of arrays my $number_of_queries = scalar @all_queries; for (my $i = 0 ; $i < $number_of_queries; ++$i) { my %query = %{ pop @all_queries }; # value of pop() is a hash foreach my $query_key (keys %query) { # Treat each value in %queries_by_key as an anonymous array push @{ $queries_by_key{$query_key} }, $query{$query_key}; } } foreach my $key (sort keys %queries_by_key) { print "$key has "; print join ',', @{ $queries_by_key{$key} }; # treat as an array print "\n"; }

    I tried to make this clear, but the syntax is kinda confusing. Hopefully they'll explain it better in the book.

    Hope this helps,

    Chris

      Here's my refactoring of chayashida's fine illustration:

      #!perl use strict; use warnings; my @all_queries; # Array of hashes my %queries_by; # Hash of arrays push @all_queries, { foo => 20 }; push @all_queries, { bar => 30 }; push @all_queries, { foo => 10 }; push @all_queries, { zen => 90 }; push @all_queries, { zen => 1 }; for my $query (@all_queries) { my ($query_key, $query_value) = %$query; push @{ $queries_by{$query_key} }, $query_value; } for my $query_key (sort keys %queries_by) { my @query_values = sort { $a <=> $b } @{ $queries_by{$query_key} } +; my $query_values = join ',', @query_values; print "$query_key has $query_values\n"; } __END__ bar has 30 foo has 10,20 zen has 1,90
Re: 'group by query' from array of hashes
by Jim (Curate) on Jan 29, 2011 at 02:48 UTC

    Here's my riff on wind's illustration:

    #!perl
    
    use strict;
    use warnings;
    use utf8;
    use open qw( :utf8 :std );
    
    my @players = qw( Bob Carol Ted Alice );
    my @deals;   # Array of hashes of cards (values) dealt to players (keys)
    my %hand_of; # Hash of arrays of cards in players' (keys) hands
    
    push @deals, { Bob   => '7♦' };
    push @deals, { Carol => 'K♣' };
    push @deals, { Ted   => '2♥' };
    push @deals, { Alice => '4♥' };
    
    push @deals, { Bob   => 'A♣' };
    push @deals, { Carol => 'Q♣' };
    push @deals, { Ted   => '3♦' };
    push @deals, { Alice => 'J♠' };
    
    push @deals, { Bob   => '5♠' };
    push @deals, { Carol => 'A♠' };
    push @deals, { Ted   => '9♣' };
    push @deals, { Alice => 'K♦' };
    
    push @deals, { Bob   => '3♠' };
    push @deals, { Carol => 'Q♠' };
    push @deals, { Ted   => 'J♦' };
    push @deals, { Alice => '6♦' };
    
    push @deals, { Bob   => 'Q♦' };
    push @deals, { Carol => 'Q♥' };
    push @deals, { Ted   => '7♠' };
    push @deals, { Alice => '5♦' };
    
    for my $deal (@deals) {
        my ($player, $card) = %$deal;
        push @{ $hand_of{$player} }, $card;
    }
    
    for my $player (@players) {
        my $hand = join ' ', @{ $hand_of{$player} };
        print "$player has $hand\n";
    }
    
    __END__
    Bob has 7♦ A♣ 5♠ 3♠ Q♦
    Carol has K♣ Q♣ A♠ Q♠ Q♥
    Ted has 2♥ 3♦ 9♣ J♦ 7♠
    Alice has 4♥ J♠ K♦ 6♦ 5♦
    

Re: 'group by query' from array of hashes
by bplegend (Novice) on Jan 29, 2011 at 16:49 UTC
    Thank you very much for your input. It was great.