http://www.perlmonks.org?node_id=932303

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

I am learning to use the "map". Naturally I have been some question. For example:

my @numero = (1..100); my %lista = map{$_,$_*2} @numero; while (($num, $doble)= each(%lista)) { print "$num .... $doble\n";}

Here $ _ * 2 does not modify $ _ and the result is as expected:

33 .... 66
32 .... 64
90 .... 180
63 .... 126
21 .... 42
71 .... 142
7 .... 14 ...

Instead, working with regexp $ _ variable itself is modified:

my @palabras = qw ( arriba abajo contigo compaņero cariņo superfluo vi +da); my %cosa = map {$_, $_=~s/a/X/g} @palabras; while (($uno, $dos)=each(%cosa)){print "$uno...$dos\n";}

And the result is not

arriba...XrribX
abajo...XbAjo ....
etc...

but

superfluo...
XbXjo...2
contigo...
compXņero...1

Where the %cosa key appears modified by ~ s and receives the number of substitutions made as value. It is also logical.

How do I use regexp and map if I want to have as a key each word in the array and assign it as value the result of a regexp operation on this key?

Replies are listed 'Best First'.
Re: map and regexp. An newbie question
by davido (Cardinal) on Oct 19, 2011 at 06:51 UTC

    Within map, $_ is an alias to each array element (one per iteration). So if you modify $_, you modify the array element to which it is aliased for a given iteration.

    The s/// operator is returning the number of times it matched. But what you seem to want is not the number of times, but the actual substitution. And you also want that to not affect the key.

    my %hash = map{ my $temp = $_; $temp =~ s/a/X/g; $_, $temp } @array;

    This snippet works by making a copy of the current element, then doing the substitution on that copy, and finally, returning both the original (which becomes a key) and the modified version (which becomes a value).


    Dave

      If you're using a more recent Perl, you can use the /r option to s///:

      my %hash = map {$_, $_ =~ s/a/X/gr} @array;

        Did you try that?

        The /r modifier (Perl 5.14) only solves one of the problems (it doesn't alter the original). It doesn't solve the second problem that the $_ =~ s/a/X/gr construct is not being evaluated in list context, and therefore returns the number of substitution matches, not the modified string.

        Apparently I didn't. ;) -- lousy excuse in a followup node below.


        Dave

        I knew that having an assignment operation, the behavior of Perl was logical ... But I was sure, also, that there was a way to get it simple and transparent ...Thank you, anneli!

      Thank you, Dave! Yes, you've come to understand my problem despite my incompetence with English ( and the contributions of Google Translate...) :)

Re: map and regexp. An newbie question
by ikegami (Patriarch) on Oct 19, 2011 at 07:42 UTC

    You might be interested in learning about List::MoreUtils's apply and Algorithm::Loops's Filter.

    my @a = apply { s/a/X/g } qw( arriba abajo ); # XrribX XbXjo

    They're not particularly useful in addressing your specific example, though.

      Wow; I started digging into L::MU to find out what trickery was required to let the anonymous subroutine sit there unadorned, then found myself reading perlsub for half an hour! Thanks!

      Ikegami Thanks!, I will put it in the "todo's" stack.