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

I have an array:
my @fname = ("Bob", "John", Ashley"); my @lname = ("Johnson", "Hill", "Sharp"); my @state = ("AK", "CA", "AL");

And what I am trying to do is create a hash that uses the @fname and @lname as the keys and the @state as the value to the hash.

What is the best way to do this? I have seen examples of using the map function, but I thought you could just set a hash equal to an array and it would create the hash for you.

The only problem is I don't know how to make both the first and last name arrays the key at the same time.

Any help would be appreciated.

Just to be clear, the hash should be like

{Bob Johnson} => {AK} {John Hill} => {CA}

Replies are listed 'Best First'.
Re: Creating a hash from arrays
by tangent (Parson) on Nov 02, 2013 at 19:57 UTC
    Try this:
    my %hash; for my $i (0 .. $#fname) { $hash{ "$fname[$i] $lname[$i]" } = $state[$i]; }
Re: Creating a hash from arrays
by davido (Cardinal) on Nov 02, 2013 at 20:13 UTC

    %hash = map { join( q{ }, $fname[$_], $lname[$_] ) => $state[$_] } 0 + .. $#fname;


    Update: Though it's not necessarily better in this case, it is sometimes convenient to place the map inside the key brackets of a hash slice:

    @hash{ map{ join q{ }, $fname[$_], $lname[$_] } 0 .. $#fname } += @state;


    List::MoreUtils might be fun... let's see.....:

    use List::MoreUtils qw( zip pairwise ); # ... %hash = zip @{[ pairwise { join q( ), $a, $b } @fname, @lname ]}, + @state;

    Maybe that's just ridiculous. ;)

    I should mention that if you didn't have the requirement of joining @fname and @lname stringwise, and instead were dealing with just a single list of keys, and a single list of values, the hash slice technique would be an ideal solution:

    @hash{@names} = @states;

    It doesn't get more succinct than that.


    Dave

      Thanks for all of the responses. Now I am trying to sort the resulting hash by values, not keys. Basically I need the array to be sorted alphabetically by state, not the people's name.

      I know I can just call sort on the hash keys to sort the hash, but I can't get it to work if I call sort on values.

        but I can't get it to work if I call sort on values.

        You need to create an array of the keys ordered by the associated values:

        [0] Perl> @a{ 1..26 } = reverse 'a'..'z';; @ordered = sort{ $a{$a} cmp $a{$b} } keys %a;; print "$_ :: $a{ $_ }" for @ordered;; 26 :: a 25 :: b 24 :: c 23 :: d 22 :: e 21 :: f 20 :: g 19 :: h 18 :: i 17 :: j 16 :: k 15 :: l 14 :: m 13 :: n 12 :: o 11 :: p 10 :: q 9 :: r 8 :: s 7 :: t 6 :: u 5 :: v 4 :: w 3 :: x 2 :: y 1 :: z

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        Sorting based on values rather than keys suggests you built your hash backwards -- or, if you need both directions, then perhaps you should consider a reverse lookup. BrowserUK suggests an array; another hash would not necessarily be out of the question. It would likely need to be a hash of arrays, however.

        my %personInfo = (); my %stateInfo = (); while (###) # loop through data { $personInfo{$name} = $state; push @{$stateInfo{$state}}, $name; }

        Now you can look up in either direction.

Re: Creating a hash from arrays
by Kenosis (Priest) on Nov 02, 2013 at 20:02 UTC

    An option using map:

    use strict; use warnings; use Data::Dumper; my @fname = ( "Bob", "John", "Ashley" ); my @lname = ( "Johnson", "Hill", "Sharp" ); my @state = ( "AK", "CA", "AL" ); my %hash = map { $fname[$_] . ' ' . $lname[$_] => $state[$_] } 0 .. $# +state; print Dumper \%hash;

    Output:

    $VAR1 = { 'Bob Johnson' => 'AK', 'Ashley Sharp' => 'AL', 'John Hill' => 'CA' };

    Hope this helps!

Re: Creating a hash from arrays
by Eily (Monsignor) on Nov 02, 2013 at 21:34 UTC

    You could also use List::MoreUtils, either:

    @keys = pairwise {return "$a $b"} @fname, @lname; @hash{@keys} = @state;
    or
    my $iter = each_array @fname, @lname, @state; while( ($firstName, $lastName, $state) = $iter->() ) { $hash{"$firstName $lastName"} = $state; }