1

我正在尝试减少我正在使用的代码行数,但最终遇到了一个相当简单的问题(尽管这让我很困惑,因为我刚刚开始思考参考资料)

我正在尝试以特定顺序连接多个值。我的代码如下所示。

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。为简洁起见,我只给出了四个)

4

5 回答 5

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 的回答。)

于 2009-10-19T16:00:02.647 回答
4
$return_name = map { $return_name = $return_name . $query->param($_) . $separator } @vals;

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

虽然该特定代码行要求使用join(),但如果您来自函数式编程背景,您可能更喜欢 reduce:

use List::Util 'reduce';
$return_name = reduce { $a . $query->param($b) . $separator } "", @vals;
于 2009-10-19T17:58:20.070 回答
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。一旦你学会了使用它(以及相关的结构,如grepand apply),你将能够简洁地表达使用普通循环代码构建时可能非常冗长的想法。

于 2009-10-19T18:04:01.493 回答
3

试试这个:

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

要回答您得到“4”的原因,这是因为您将结果数组的基数分配给一个标量。

于 2009-10-19T15:59:53.677 回答
1

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

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

可以写成

$return_name .= $query->param($_) . $separator;
于 2009-10-19T18:03:24.147 回答