fugu
fugu

Reputation: 6568

Create a hash in which the key is an array, and the value is an array of arrays

I'm trying to create a hash in which keys are contained in an array and values in an array of an array:

my @keys = (1,2,3,4,5);
my @value1 = (a,b,c,d,e);
my @value2 = (f,g,h,i,j);
my @value3 = (k,l,m,n,o);

my @values = ([@value1],[@value2],[@value3]);

my %hash;

I want to create a hash with @keys as keys, and @values as values so that key '1' would return the values a,f,k (0th element in each array) and so on.

For a single key this would be achieved as follows:

%hash=('key'=>@values);

But I'm unsure how to modify this for an array of keys.

Any help would be amazing!

Cheers,

N

Upvotes: 4

Views: 1881

Answers (5)

ysth
ysth

Reputation: 98378

use Algorithm::Loops 'MapCarE';
my @keys = qw(1 2 3 4 5);
my @value1 = qw(a b c d e);
my @value2 = qw(f g h i j);
my @value3 = qw(k l m n o);

my %hash = MapCarE { $_[0] => [ @_[1..$#_] ] } \(@keys, @value1, @value2, @value3);

MapCarE loops through the arrays, calling the code you supply first passing the first elements of the arrays, then the seconds element, etc.

Upvotes: 0

Jim Black
Jim Black

Reputation: 1482

Try this...

#! /usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @keys = qw( undef 0 1 $key kappa );
my @value1 = qw(a b c d e);
my @value2 = qw(f g h i j);
my @value3 = qw(k l m n o);

# not used here...
# my @values = ([@value1],[@value2],[@value3]);

my %hash = map { my $key = "$keys[$_]"; $key => [ $value1[$_], $value2[$_], $value3[$_] ] } (0..$#keys);

for my $key ( sort keys %hash ) {
    print "Key: $key contains: ";
    for my $value ( @{$hash{$key}} ) {
        print "$value ";
    }
    print "\n";
}

print "Should print 'c': ".@{$hash{'1'}}[0]."\n";
print "Should print 'j': ".@{$hash{'kappa'}}[1]."\n";

# print Dumper( %hash );

With expected output like this:

Key: $key contains: d i n 
Key: 0 contains: b g l 
Key: 1 contains: c h m 
Key: kappa contains: e j o 
Key: undef contains: a f k 
Should print 'c': c
Should print 'j': j

Adding: If you'd like to access a single value within the hash, it should be surrounded by @{} to convert the anonymous array reference, and then ended with your index (starting from zero) in square brackets, like [0]. Examples:

print "Should print 'c': ".@{$hash{'1'}}[0]."\n";
print "Should print 'j': ".@{$hash{'kappa'}}[1]."\n";

Modified to include Ekkehard's more proper usage of (0..$#..) and added some bullet proofing of the keys.

Upvotes: 2

David W.
David W.

Reputation: 107030

I take advantage of the syntax $foo[$i][$j]; to represent your array of arrays as a two dimensional array. Here's an answer sans the map:

#! /usr/bin/env perl

use 5.12.0;
use warnings;
use Data::Dumper;

my @keys = qw(alpha beta gamma delta epsolon);

my @values1 = qw(one two three four five);
my @values2 = qw(uno dos tres quatro cinco);
my @values3 = qw(a b c d e);

my @values = ( \@values1, \@values2, \@values3 );

my %hash;
for my $item ( (0..$#keys) ) {
    my @array;
    push @array, $values[0][$item], $values[1][$item], $values[2][$item];
    $hash{$keys[$item]} = \@array;
}

say Dumper \%hash;

Here's the output:

$VAR1 = {
      'gamma' => [
           'three',
           'tres',
           'c'
         ],
      'delta' => [
           'four',
           'quatro',
           'd'
         ],
      'alpha' => [
           'one',
           'uno',
           'a'
         ],
      'beta' => [
          'two',
          'dos',
          'b'
        ],
      'epsolon' => [
             'five',
             'cinco',
             'e'
           ]
    };

Looks about right. Of course, I never verified that the various arrays are all the same size.

Upvotes: 2

Vedran Šego
Vedran Šego

Reputation: 3765

Something like this:

my %hash = map { $keys[$_] => [ $value1[$_], $value2[$_], $value3[$_] ] } 0..$#keys;

assuming that all four lists have the same length.

Upvotes: 4

Ekkehard.Horner
Ekkehard.Horner

Reputation: 38745

Combining the best of Vedran's and Jim's solutions:

use strict;
use warnings;

# my @keys   = ( 1,  2,  3,  4,  5);
my @keys   = ( 'alpha','beta','gamma','delta','epsilon');
my @value1 = ('a','b','c','d','e');
my @value2 = ('f','g','h','i','j');
my @value3 = ('k','l','m','n','o');

my %hash = map { $keys[$_] => [ $value1[$_], $value2[$_], $value3[$_] ] } (0 .. $#keys);
printf 'first (%s) value: [%s]', $keys[0], join ", ", @{$hash{$keys[0]}};

output:

first (alpha) value: [a, f, k]

or:

first (1) value: [a, f, k]

depending on which @keys you choose.

Upvotes: 1

Related Questions