narashima has asked for the wisdom of the Perl Monks concerning the following question:
Revered Monks,
I have a csv file that has 2 comma seperated values.
eg. a, b
c, d
e, f
I am trying to slurp this file in and append a string(in this example the string I am trying to append is 'hi' ) to these values. Below is what I am doing
@new= map {s/$_/$_,hi/} <TEST>;
I am expecting something like:
a, b, hi
c, d, hi
e, f, hi
But this does not work. When I dump @new using Data::Dumper I get the following output:
$VAR1 = 1;
$VAR2 = 1;
$VAR3 = 1;
Could someone please tell me what I am doing wrong?
Thanks!
Re: Using regex in Map function
by merlyn (Sage) on May 02, 2007 at 22:21 UTC
|
You'd probably be even more surprised by the result of this:
my @in = qw(aaa bbb ccc);
my @out = map { s/.$/x/ } @in;
print "@in\n=>\n@out\n";
which prints:
aax bbx ccx
=>
1 1 1
Yeah, the original is modified. Basically: never modify $_ in a map, and remember that the "output" of s/// is the success count/code. To get what you want, you need to localize $_ and reuse it as the last expression evaluated in the block:
my @in = qw(aaa bbb ccc);
my @out = map { local $_ = $_; s/.$/x/; $_ } @in;
print "@in\n=>\n@out\n";
which indeed shows:
aaa bbb ccc
=>
aax bbx ccx
| [reply] [d/l] [select] |
|
my @out = map {substr ($_, 0, -1) . 'x'} @in;
Prints:
aaa bbb ccc
=>
aax bbx ccx
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
|
my @out = map { (my $s = $_) =~ s/.$/x/; $s } @in;
AIUI in blead/5.10 the following should also work just in the same manner:
my $_;
# ...
my @out = map { s/.$/x/; $_ } @in;
| [reply] [d/l] [select] |
|
Hi Blazer & Randal,
Could you guys please explain why we need to localize $_ inside the map? I am not sure I understand why we need to do this.I seem to get the same result even if I do not localize $_. Is there something I am missing?
Thanks!
| [reply] |
|
|
************** Bad Program ****
my @in = qw(a b c d e f g h);
print "Start: ",@in,"\n","***RUNNING MAP***\n\n";
my @out = map { s/.$/x/} @in;
print "in : ",@in,"\n";
print "out: ",@out,"\n"
************* Output ******
Start: abcdefgh
***RUNNING MAP***
in : xxxxxxxx
out: 11111111
*********************
Comment #1:
Use "r" feature on regex
************** fixed Program ****
my @in = qw(a b c d e f g h);
print "Start: ",@in,"\n","***RUNNING MAP***\n\n";
my @out = map { s/.$/x/r} @in;
print "in : ",@in,"\n";
print "out: ",@out,"\n"
************* Output ******
Start: abcdefgh
***RUNNING MAP***
in : abcdefgh
out: xxxxxxxx
****************
Comment #2
But what if you REALLY wanted the return value of the regex - and not modify the original output? (why? I don't know)
Localize the input...
************** fixed Program ****
my @in = qw(a b c d e f g h);
print "Start: ",@in,"\n","***RUNNING MAP***\n\n";
my @out = map { s/.$/x/} my @temp = @in;
print "in : ",@in,"\n";
print "out: ",@out,"\n"
************* Output ******
Start: abcdefgh
***RUNNING MAP***
in : abcdefgh
out: 11111111
| [reply] [d/l] [select] |
|
You're replying to my note from 2007 with a feature that has only been available for a few releases. Nice.
-- Randal L. Schwartz, Perl hacker
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
| [reply] |
|
Re: Using regex in Map function
by jdporter (Paladin) on May 02, 2007 at 21:09 UTC
|
You need to remember that the result of map is the list of the final value of each pass through its block. The value of s/// is a boolean indicating whether a replacement was made. You want the final value of the map block to be $_. Like so:
@new = map { s/$_/$_,hi/; $_ } <TEST>;
However, your substitution is less than ideal. In particular, you'll have problems if $_ contains any regex-special characters. If you're simply appending, you could do this:
@new = map { s/$/,hi/; $_ } <TEST>;
or, even betterworse, this:
@new = map { $_ . ',hi' } <TEST>;
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] [select] |
|
# given
$x = 'abacad';
# then
$x =~ s/a/z/; # returns 1
$x =~ s/a/z/g; # returns 3
$x =~ s/x/z/; # returns empty string, not undef
... although it can be treated quite nicely in a boolean manner :)
• another intruder with the mooring in the heart of the Perl
| [reply] [d/l] |
|
@new = <TEST>;
s/something/something/ for @new;
I haven't Benchmarked it or anything, but I'm pretty sure it's faster than map {s/regex/stuff/} — either way, it's probably more readable.
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
sub cwmap( &@ ) {
map {
local $_ = $_; # create copy
$_[0]->(); # execute code-block
$_; # copied element
} @_[ 1..$#_ ]; # list
} # cwmap
# and then use it like map:
@new = cwmap { s/$_/$_,hi/ } <TEST>;
Best regards,
perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"
| [reply] [d/l] |
Re: Using regex in Map function
by BrowserUk (Patriarch) on May 02, 2007 at 23:13 UTC
|
my @new;
( $new[ @new ] = $_ ) =~ s[$][,hi] while <DATA>;
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.
| [reply] [d/l] |
Re: Using regex in Map function
by naikonta (Curate) on May 03, 2007 at 04:44 UTC
|
I'm not really sure about your exact requirement, but should it's really that simple regex, simple concatenation will do as well.
my @orig = qw(a,b c,d e,f);
my $extra = 'hi';
my @new = map { $_ .= ",$extra" } @orig;
print "orig: [@orig] => new: [@new]\n";
# orig: [a,b,hi c,d,hi e,f,hi] => new: [a,b,hi c,d,hi e,f,hi]
This way, you append the line and return it as well from map().
Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!
| [reply] [d/l] [select] |
|
|