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

Dear Monks,
I have two main questions. Firstly how can I create a hash from three arrays (of the same length) with one array containing the keys and the other two as values to the keys?

My second question is how can I match values in a fourth array to the hash and then extract the corresponding values if they match?
Thank you for you patience!

Replies are listed 'Best First'.
Re: hashes with multiple values per key
by TedYoung (Deacon) on Jan 24, 2005 at 13:41 UTC

    Hi

    To your first question: you can have multiple values per key by using an array reference as the value:

    my (@keys, @values1, @values2); my %hash; for (0 .. $#keys) { $hash{$keys[$_]} = [ $values1[$_], $values2[$_] ]; }

    A more compact method would use an hash slice and map:

    @hash{ @keys } = map { [ $values1[$_], $values2[$_] ] } 0 .. $#values1 +;

    Now, for a give key, here is how you can get the values:

    # Return as an array: @values = @{ $hash{ $key } }; print $values[0]; # Return as an array ref: $values = $hash{ $key }; print $values->[0];

    As for your second question: you can use a hash slice, again, to fetch a list of values based on a list of keys:

    @values = @hash{ @keys }; for (@values) { print $_->[0], $_->[1]; }

    A very important thing with this is watch the sigils (i.e. $, @, %) very closely.

    More Information:

    perldata has information about hashes and subscripts.

    perlref has information about references and dereferencing.

    Ted Young

    ($$<<$$=>$$<=>$$<=$$>>$$) always returns 1. :-)
Re: hashes with multiple values per key
by edan (Curate) on Jan 24, 2005 at 13:35 UTC
    my %hash; for my $i ( 0 .. $#keys ) { $hash{ $keys[$i] } = [ $values1[$i], $values2[$i] ]; } for my $value ( @values3 ) { if ( exists $hash{ $value } ) { print @{ $hash{ $value } }; } }

    disclaimer: UNTESTED

    --
    edan

Re: hashes with multiple values per key
by saskaqueer (Friar) on Jan 24, 2005 at 13:37 UTC

    The wording of your question is not too clear, so I'll do my best to guess at what you want. This answers part one of your question, assuming you want the data structure shown after the __END__ token:

    my @hash_keys = qw(keyone keytwo keythree); my @hash_vals1 = qw(val1 val2 val3); my @hash_vals2 = qw(val4 val5 val6); my %the_hash; $the_hash{ $hash_keys[$_] } = [ $hash_vals1[$_], $hash_vals2[$_] ] for ( 0 .. $#hash_keys ); __END__ %the_hash = ( keyone => [ qw(val1 val4) ], keytwo => [ qw(val2 val5) ], keythree => [ qw(val3 val6) ] );

    update: I'm not sure what you mean by question #2. What has to match for you to want the values?

Re: hashes with multiple values per key
by holli (Abbot) on Jan 24, 2005 at 13:37 UTC
    use strict; use Data::Dumper; my @a = (1,2,3); my @b = (4,5,6); my @c = (7,8,9); my %h; for (0..$#a) { $h{$a[$_]} = [$b[$_], $c[$_]]; } my @d = (1,3); for ( @d ) { print join ("*",@{$h{$_}}), "\n" if $h{$_}; }
    Update: Wow. 3 x 13:37, and 1 x 13:35. That is timing ,)

    holli, regexed monk
Re: hashes with multiple values per key
by Fletch (Bishop) on Jan 24, 2005 at 13:37 UTC

    perldoc perlreftut and perldoc perldsc should be your first stop. Sounds like you want a hash of arrayrefs.

    my @keys = qw( a b c ); my @val1 = ( 1, 2, 3 ); my @val2 = ( 2, 4, 6 ); my %hoa; my $idx = 0; for my $k ( @keys ) { @{ $hoa{ $k } } = [ $val1[ $idx ], $val2[ $idx ] ]; $idx++; }

    Update: Feh, need more caffeine. As is remarked below it of course should be $hoa{ $k } = [ ... ]. Otherwise you get an extra arrayref around things.

      @{ $hoa{ $k } } = [ $val1[ $idx ], $val2[ $idx ] ];

      I think you'd either want to remove the @{} notation, or else change your square brackets to parentheses. Your line there is creating a strange data structure there :)

      # this @{ $hoa{ $k } } = ( $val1[ $idx ], $val2[ $idx ] ); # or this $hoa{ $k } = [ $val1[ $idx ], $val2[ $idx ] ];