为什么我的Perl地图列表只返回1?

Hai*_*ang 7 perl map

我写的代码如下:

#!/usr/bin/perl 

my @input = ( "a.txt" , "b.txt" , "c.txt" ) ;
my @output = map { $_ =~ s/\..*$// } @input ;

print @output ;
Run Code Online (Sandbox Code Playgroud)

我的目的是让没有扩展名的文件名存储在数组中@output.但它改为存储返回的值s///而不是更改的文件名@output,因此结果如下

1
1
1
Run Code Online (Sandbox Code Playgroud)

那么map在这种情况下使用的正确方法是什么?

bri*_*foy 19

在所有这些答案中,没有人只是说map返回最后一个评估表达式的结果.无论你最后做什么,事情(或事物)都会map回归.它就像一个子程序或do返回结果的最后一个计算表达式.

Perl v5.14添加了非破坏性替换,我在使用/ r替换标志来处理副本.它不返回替换次数,而是返回修改后的副本.使用/r标志:

my @output = map { s/\..*$//r } @input;
Run Code Online (Sandbox Code Playgroud)

请注意,您不需要使用$_绑定运算符,因为这是默认主题.

  • 感谢您指出我不知道的`/ r`标志. (3认同)

der*_*ert 16

好的,首先,您可能想要$_ =~ s/\..*$//- 请注意s您的示例中缺少的内容.另外,你可能map不是grep.

其次,这不符合你的要求.这实际上是修改@input!内部grep(以及map其他几个地方)$_实际上是每个值的别名.所以你实际上是在改变价值.

另请注意,模式匹配不会返回匹配的值; 它返回true(如果有匹配)或false(如果没有).这就是你所看到的所有1.

相反,做这样的事情:

my @output = map {
    (my $foo = $_) =~ s/\..*$//;
    $foo;
} @input ;
Run Code Online (Sandbox Code Playgroud)

第一个复制$_$foo,然后修改$foo.然后,它返回修改后的值(存储在其中$foo).你不能使用return $foo,因为它是一个块,而不是子程序.

  • List :: MoreUtils http://search.cpan.org/perldoc/List::MoreUtils提供`apply`,非常适合这类事情.它的工作方式类似于`map`,但不会改变数组参数中的值.`使用List :: MoreUtils'apply'; 我的@output = apply {s /\..*$ //} @input;` (5认同)

inn*_*naM 7

$_已经讨论了列表值的别名问题.

但更重要的是:你的问题的标题清楚地说"地图",但你的代码使用grep,虽然它看起来真的应该使用map.

grep将评估您提供的列表中的每个元素作为第二个参数.在列表上下文中,它将返回一个列表,该列表包含表达式返回true的原始列表的那些元素.

map 另一方面,使用表达式或块参数来转换list参数的元素,返回一个新的列表,该列表由原始的转换参数组成.

因此,您的问题可以通过以下代码解决:

@output = map { m/(.+)\.[^\.]+/ ? $1 : $_ } @input;
Run Code Online (Sandbox Code Playgroud)

这将匹配不是扩展名的文件名部分,并作为评估结果返回,如果没有扩展名,则返回原始名称.