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

I was wondering if it is possible to convert an array (that needs splitting) to hash key/values using map. I tried several Super Searches, looked under Categorized Q&A, in the Perl Cookbook and Programming Perl 2nd Edition but couldn't find examples similar to what I'm looking for:
use strict; use warnings; my @array = qw(key1:value1 key2:value2 key3:value3); my (%hash, $key, $val); foreach (@array) { ($key, $val) = split ":"; $hash{$key} = $val; } print "\$hash{$_} = $hash{$_}\n" foreach keys %hash;
I want replace the foreach (@array) with something like this: %hash = map {# what the heck goes here?} @array; I haven't used map much, but would like to start using it more often where appropriate. Maybe the question should be "Is it appropriate in this example?". TIA,

--Jim

Replies are listed 'Best First'.
Re: Using map to split an array to hash key/values
by Masem (Monsignor) on Dec 18, 2001 at 02:45 UTC
    Map will return an array, but when you assign it to a hash, all the hash expects is a even-numbered array. So just assign, on each map step, the key/value pair:
    %hash = map { my ( $key, $value ) = split ":"; ( $key, $value ) } @arr +ay; #OR %hash = map { my ( $key, $value ) = split ":"; $key => $value } @array +; #OR %hash = map { split( ":", $_, 2 ) } @array;
    (In the last case, I only want 2 elements from the split, just in case "testkey:extra:colon" might exist.)

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

      Using a string as split's first argument is confusing if it's not a single whitespace (\x20). It'll still be interpreted as a regex, which is not what one would expect.
      Simplifying split might make it into perl6, but we'll have to live with its current rules for now. Read RFC 361, the most important statement (imho) is: "Yes, split '.', $foo doesn't split on dot -- it's currently the same an split /./, $foo.)".

      2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: Using map to split an array to hash key/values
by FoxtrotUniform (Prior) on Dec 18, 2001 at 02:40 UTC

    How 'bout:

    my %hash = map {split /:/} @array;

    You can construct hashes from lists; for example, explicit hash construction (key => val) just makes a list from a hash (the => operator is a glorified comma).

    --
    :wq
Re: Using map to split an array to hash key/values
by mortis (Pilgrim) on Dec 18, 2001 at 02:40 UTC
    You can think of map as a function that takes a sub and an array as arguments. It then calls the sub for every element of the array. It accumulates the values returned from all of those function calls and returns them as a list.

    To fill the hash by assigning to it, you need to have a list that consists of key/value pairs - which you were obtainig before via split. You can do the same thing:

    my %hash = map { split /:/; } @array;
    Split will break each element of @array into a key/value pair (just like your code does), and map will accumulate them into a list, then you assign the list to the hash.

    Is that what you were after?

Re: Using map to split an array to hash key/values
by Juerd (Abbot) on Dec 18, 2001 at 02:44 UTC
    You can just assign a list to a hash: %hash = qw(key1 value1 key2 value2);
    Map iterates over its given list and evaluates its expression, creating a list of returned values.
    @array = ('key1:value1', 'key2:value2', qw(key3:value3 key4:value4 key +5:value5)); # Hope this helps beginners to understand what qw// does... %hash = map { split /:/, $_, 2 } @array;
    Use split's 3-argument form to avoid having a broken hash when one of @array's elements is something "foo:bar:baz"

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: Using map to split an array to hash key/values
by jlongino (Parson) on Dec 18, 2001 at 02:53 UTC
    I was afraid that there would be a simple solution. I just didn't realize how simple. Turns out I was trying things that were much too complicated (none of which worked). Thanks for the quick and accurate replies. The solution will definitely find its way into my regular coding practice. I feel like an idiot, allbeit a slightly more enlightened one now. :)

    Obviously I need to study more map examples. Thanks All!

    --Jim

      Oh well in that case I think Erudil might be able to give you a few pointers.

      --
      g r i n d e r
      just another bofh

      print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u';
Re: Using map to split an array to hash key/values
by strat (Canon) on Dec 18, 2001 at 19:32 UTC
    BTW: if you want to split something into two pieces, then better tell split to do so:
    my ($key, $value) = split(/: /, $string, 2);
    or:
    my ($key, $value) = split(/\s*\:\s*/, $string, 2);

    Best regards,
    perl -e "print a|r,p|d=>b|p=>chr 3**2 .7=>t and t"

Re: Using map to split an array to hash key/values
by jsegal (Friar) on Dec 18, 2001 at 02:44 UTC
    how about
    my @array = qw(key1:value1 key2:value2 key3:value3); my %hash = map {split ":"} @array; # .. etc ..
    Map evaluates in array context, and if the block in the map clause returns an array (like split does), the elements will be interpolated. This then gets interpreted as a hash. Best of luck.... -Jonathan