views:

143

answers:

5

Hello! I am trying to cut down on the number of code lines I am using but am ending up with a fairly simple problem (although it's stumping me since I am just starting to wrap my head around references)

I am trying to concatenate several values in a particular order.. My code looks like this..

my $separator = ":";
my @vals = qw(name last-name first-name phone);
my $return_name;
$return_name = map { 
    $return_name = $return_name . $query->param($_) . $separator 
} @vals;

What I am getting is "4", instead of concantenating all into one string.

What I am trying to achieve is a shorter version of ...

$return_name = $query->param('name') . 
    $separator . $query->param('last-name') . 
    $separator . $query->param('first_name') . 
    $separator . $query->param('phone');

(I'm actually trying to string together about 25 $query->params. I only gave four for brevity)

+4  A: 

Try this:

join $separator, 
     map { $query->param($_) } 
     ("name", "last-name", "first-name", "phone");

To answer the reason you get '4', it is because you are assigning the resulting arrays' cardinality to a scalar.

dsm
+4  A: 

map returns a list, not a string. Try this:

$return_name = join $separator, map { $query->param($_) } @vals;

Or if you really want to cut the number of lines, try this:

my $return_name = join ':', 
    map { $query->param($_) } 
    qw(name last-name first-name phone);

(The one-line version was inspired by dsm's answer.)

jbourque
I am sure dsm's above worked too. jbourque it works like a champ! Thanks!
Nikki
+4  A: 
$return_name = map { $return_name = $return_name . $query->param($_) . $separator } @vals;

That's a scalar assignment, which gives the map operation scalar context. map in scalar context returns a count of the elements that would have been produced.

While that particular line of code cries out for the use of join(), if you come from a functional programming background, you may be more comfortable with reduce:

use List::Util 'reduce';
$return_name = reduce { $a . $query->param($b) . $separator } "", @vals;
ysth
+1  A: 

In addition to all the good answers you have received, note that

$return_name = $return_name . $query->param($_) . $separator;

can be written as

$return_name .= $query->param($_) . $separator;
Sinan Ünür
+4  A: 

Part of your problem is confusion over how map works.

map takes a list of arguments, performs an operation on the elements of the list and creates a new list from the results. In scalar context it returns the number of members in the new list.

In most cases you don't want to do an assignment in the map operation.

# no assignment needed to set @foo
my @foo = map $_+2, 1,2,3; 
# @foo = (3,4,5);

The one place where assignment makes sense is if you need to use an operation that would normally change the value of $_, but you need to preserve the arguments to map unchanged.

That explanation is not terribly clear. Check out these examples, they should help clarify what I am saying. The first shows you map can alter the values it processes:

my @foo = qw( fee fie foe fum );
my @bar = map { s/e/-/g } @foo;
# @foo = ( 'f--', 'fi-', 'fo-', 'fum' ); 
# @bar = ( 2, 1, 1, '' );

To avoid altering @foo you can do:

my @foo = qw( fee fie foe fum );
my @bar = map { my $val = $_; $val =~ s/e/-/g } @foo;
# @foo = ( 'fee', 'fie', 'foe', 'fum' ); 
# @bar = ( 'f--', 'fi-', 'fo-', 'fum' );

Or you can do:

use List::MoreUtils qw( apply );

my @foo = qw( fee fie foe fum );
my @bar = apply { s/e/-/g } @foo;
# @foo = ( 'fee', 'fie', 'foe', 'fum' ); 
# @bar = ( 'f--', 'fi-', 'fo-', 'fum' );

At its most basic map works like a specialized form of a for loop. The two chunks of code produce the exact same result:

my @foo = map {$_ * 2} 1..5;

my @bar;
for (1..5) {
     my $val = $_ * 2;
     push @bar, $val;
}

I hope this have given you some help in learning how to think about map. Once you have learned to use it (and related constructs like grep and apply) you will be able to concisely express ideas that can incredibly verbose when built using normal looping code.

daotoad
daotoad, that was the best answer I could have gotten for this. I mean everyone has been incredibly helpful but your answer really helped me most to understand it.
Nikki