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

Easy question:
I am trying to understand how the map function works. Let's say we have an arbitrary list as such:
my @words = ('one-', 't-wo', 'three- fo-ur', 'five six se-ven');

My goal is to remove all dashes and split the elements on white space, i.e. I want the new list to look like:

qw(one two three four five six seven)

The question: (drum roll please)
why does this work:

print join("\n", map { $_ =~ s/-//g; split; } @words);
and this one does not:
print join("\n", map { $_ =~ s/-//g } map { split } @words);

I know it has something to do with what the right map statement returns: does it return a reference to an array or an array?

Thanks!

Replies are listed 'Best First'.
Re: Fun with learning maps
by chromatic (Archbishop) on Jun 27, 2000 at 01:24 UTC
    map usually returns a list.

    It also returns the last value of the inner block, for each element of the provided list. The output of '1111001' matches those members of @words that have the - character removed from them. Hmm. print join "\n", map { tr/-//d; $_ }  map { split/\s+/ } @words; or print join "\n", map { tr/-//d; split/\s+/; $_ } @words ; work. (You can even remove the $_ statement in the second one -- I left it in there so there would be no doubt about the last statement in the block.)

    The first example you provided works correctly because the last statement of the first map block (which is the last one evaluated) returns the words. The second one does not, because, in the scalar context, tr/// returns the number of successful transliterations (1 or 0 in your example).

    (Adam pointed out that my original explanation of tr/// fit the facts, but was wrong.)

      and chromatic returns very useful answers thanks
RE: Fun with learning maps
by Adam (Vicar) on Jun 27, 2000 at 01:46 UTC
    They both work. They just do different things. Remember that the return value of a block is the return value of the last command executed. So in the first one you remove the hyphens first and then split on white space... returning the substrings from the splits. The second version splits on white space, passing the sub strings to the left map which then removes the hyphens and returns the number of hyphens removed which is then passed to the join.
RE: Fun with learning maps
by Anonymous Monk on Jun 28, 2000 at 01:37 UTC
    I just had to add a bit more to this. The alternate form of the code that would have helped jeffa the most was: print join("\n", map { split; $_ =~ s/-//g;} @words); With the split and substitution reversed, you would have discovered quite quick that s/// and tr/// always return counts, even in the list context that map provides. I bet you have seen foreach (/PATTERN/) {} and figured that s/// and tr/// work like m// does in that idiom. Read a bit of `perldoc perlop` and you will find that in the section "Regexp Quote-Like Operators" it explains m// behavior in a list (returns the list of matches) but makes no such claims about the other two. This has bit me before. =) BTW, with your first example and with the others that were provided, you should also do a: print join("\n", @words); And note the side effects of your code on your original data.
      Now that is very interesting:
      My first try produces the desired output, but it mangles the original data: in particular the dashes are removed, but there are still 4 elements as opposed to 7.

      The second try does not produce the desired output (it returns the truth of the substituion match), but the original data is intact.

      Very interesting . . . I will study this more, but now it's time for rush hour traffic!!

      Thanks all!