为什么这张地图会返回一个数字?

时间:2009-10-19 15:56:36

标签: perl arrays string-concatenation

我正在努力减少我正在使用的代码行的数量,但最终会遇到一个相当简单的问题(尽管由于我刚刚开始围绕引用而烦恼我)

我试图按特定顺序连接几个值。我的代码看起来像这样..

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;

我得到的是“4”,而不是将所有内容连成一个字符串。

我想要实现的是......的简短版本。

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

(我实际上是想把大约25 $query->params串起来。为了简洁起见,我只给了四个)

5 个答案:

答案 0 :(得分:4)

map返回一个列表,而不是字符串。试试这个:

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

或者,如果你真的想减少行数,试试这个:

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

(单行版的灵感来自dsm的回答。)

答案 1 :(得分:4)

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

这是一个标量赋值,它给出了map操作标量上下文。 标量上下文中的map返回将要生成的元素的计数。

虽然特定的代码行急需使用join(),但如果你来自函数式编程背景,那么你可能更适合使用reduce:

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

答案 2 :(得分:4)

您的部分问题是map如何运作的混淆。

map获取参数列表,对列表元素执行操作,并根据结果创建新列表。在标量上下文中,它返回新列表中的成员数。

在大多数情况下,您不希望在map操作中执行任务。

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

赋值有意义的一个地方是,如果您需要使用通常会更改$_值的操作,但您需要保留参数以保持映射不变。

这种解释并不十分清楚。看看这些例子,它们应该有助于澄清我在说什么。第一个显示您的地图可以改变它处理的值:

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

为了避免改变@foo,你可以这样做:

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' ); 

或者你可以这样做:

使用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' );

最基本的map就像for循环的特殊形式一样。两个代码块产生完全相同的结果:

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

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

我希望这能帮助你学习如何思考map。一旦你学会了使用它(以及grepapply之类的相关结构),你就能够简明扼要地表达在使用普通循环代码构建时非常冗长的想法。

答案 3 :(得分:3)

试试这个:

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

要回答你得到'4'的原因,那是因为你将结果数组的基数分配给标量。

答案 4 :(得分:1)

除了收到的所有好答案外,请注意

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

可以写成

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