Clovis_Sangrail has asked for the wisdom of the Perl Monks concerning the following question:
Hello Esteemed Monks,
I'm trying to do stuff the Perl way, not the "old 'C' programmer futzing with Perl" way, so I decided to try and strip off the path portion of a directory listing with the Perl map function. I have a list like:
my @oldlist = qw X /etc/passwd /etc/group /etc/shadow X;
And I thought to map it into a new list without the "/etc/" part via:
my @newlist = map s/\/etc\/// , @oldlist;
But that is nothing like what happened! Here is a sample program that runs this stuff (with an extra, non-matching input list element) and prints the output:
$ $ cat t.pl #!/usr/bin/perl use strict; use warnings; my @oldlist = qw X /etc/passwd /etc/group /egg/drop /etc/shadow X; my @newlist = map s/\/etc\/// , @oldlist; print "\nAfter map (newlist)\n"; print "=========\n"; foreach (@newlist) { print "$_\n"; } $ ./t.pl After map (newlist) ========= 1 1 1 $
WTF?? Now, actually I *am* an old 'C' programmer futzing with Perl, so instead of messing with the debugger I just printed everything out before and after the map:
$ cat ta.pl #!/usr/bin/perl use strict; use warnings; my @oldlist = qw X /etc/passwd /etc/group /egg/drop /etc/shadow X; print "\nBefore map (oldlist)\n"; print "==========\n"; foreach (@oldlist) { print "$_\n"; } my @newlist = map s/\/etc\/// , @oldlist; print "\nAfter map (oldlist)\n"; print "=========\n"; foreach (@oldlist) { print "$_\n"; } print "\nAfter map (newlist)\n"; print "=========\n"; foreach (@newlist) { print "$_\n"; } $ ./ta.pl Before map (oldlist) ========== /etc/passwd /etc/group /egg/drop /etc/shadow After map (oldlist) ========= passwd group /egg/drop shadow After map (newlist) ========= 1 1 1 $
How can this be?? The documentation in the "intermediate Perl" book (where I'm try'ing to do chap1 ex2) says that the map function loads each member of the source list into $_ , evaluates the mapping expression in list context (which I figured would make a 1-element list, substituting a null string for the "/etc/" part if matched in $_) , and then puts (shifts?) the resulting list into the new resulting list. But *MY* map function is altering @oldlist !?!? I guess that something a little more complicated than the text is going on, something involving references instead of values being loaded in $_, so I decided I'd try using the block form of map, and make a separate local variable in the block to work the substitution upon, like so (after realizing I had to lose the ','):
my @newlist = map { my $l = $_; $l =~ s/\/etc\///; } @oldlist;
With a new string, I should have nothing more whatsoever to do with @oldlist, right? And yet:
$ ./tb.pl Before map (oldlist) ========== /etc/passwd /etc/group /egg/drop /etc/shadow After map (oldlist) ========= /etc/passwd /etc/group /egg/drop /etc/shadow After map (newlist) ========= 1 1 1 $
Now I'm not messing with the source list any more, but I am still getting a boolean or numeric context out of my block! Page 54 of my "Learning Perl" book ends the discussion of "forcing scalar context" with "...there's no corresponding function to force list context. It turns out never to be needed." I'm not so sure anymore... I have to create yet another local variable in the block to get the behavior I'm looking for ('before' print removed for brevity):
$ cat tc.pl #!/usr/bin/perl use strict; use warnings; my @oldlist = qw X /etc/passwd /etc/group /egg/drop /etc/shadow X; my @newlist = map { my $l = $_; $l =~ s/\/etc\///; my $l2 = $l; } @oldlist; print "\nAfter map (oldlist)\n"; print "=========\n"; foreach (@oldlist) { print "$_\n"; } print "\nAfter map (newlist)\n"; print "=========\n"; foreach (@newlist) { print "$_\n"; } $ ./tc.pl After map (oldlist) ========= /etc/passwd /etc/group /egg/drop /etc/shadow After map (newlist) ========= passwd group /egg/drop shadow $
So, why do I have to go thru all this? Why doesn't my original map function just put out the final value of the $_ variable?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Unexpected behavior with "map"
by runrig (Abbot) on Mar 12, 2014 at 18:59 UTC | |
|
Re: Unexpected behavior with "map"
by toolic (Bishop) on Mar 12, 2014 at 19:03 UTC | |
|
Re: Unexpected behavior with "map"
by kcott (Archbishop) on Mar 12, 2014 at 21:37 UTC | |
|
Re: Unexpected behavior with "map"
by fishmonger (Chaplain) on Mar 12, 2014 at 19:12 UTC | |
|
Re: Unexpected behavior with "map"
by TomDLux (Vicar) on Mar 13, 2014 at 03:14 UTC | |
|
Re: Unexpected behavior with "map"
by Clovis_Sangrail (Beadle) on Mar 12, 2014 at 21:06 UTC |