如何在元素方面对两个列表求和

时间:2012-05-23 09:11:43

标签: perl list

我想逐行解析一个文件,每个文件包含两个整数,然后将这些值加在两个不同的变量中。我天真的做法是这样的:

my $i = 0;
my $j = 0;
foreach my $line (<INFILE>)
{
    ($i, $j) += ($line =~ /(\d+)\t(\d+)/);
}

但它会产生以下警告:

  

在void上下文中无用的私有变量

暗示使用+ =运算符触发标量中左侧的评估而不是列表上下文(如果我在这一点上错了,请纠正我。)

是否有可能在不使用数组或中间变量的情况下优雅地实现(可能在一行中)?


相关问题:How can I sum arrays element-wise in Perl?

4 个答案:

答案 0 :(得分:6)

不,这是因为表达式($i, $j) += (something, 1)解析为仅将1添加到$j,而$i挂在void上下文中。 Perl 5没有超级运算符或自动压缩赋值运算符,例如+=。这有效:

my ($i, $j) = (0, 0);
foreach my $line (<INFILE>) {
    my ($this_i, $this_j) = split /\t/, $line;
    $i += $this_i;
    $j += $this_j;
}

您可以通过使用复合数据结构而不是列的命名变量来避免重复。

答案 1 :(得分:3)

首先,你成对添加数组的方法不起作用(你自己发布的相关问题会给出一些提示)。

对于解析部分:如何分割线条?如果您的行格式相应(空格不应该是一个问题)。

split(/\t/, $line, 2)

如果你真的,真的想在一行中做,你可以做这样的事情(虽然我认为你不会称之为优雅):

my @a = (0, 0);
foreach my $line (<INFILE>)
{
    @a = map { shift(@a)+$_ } split(/\t/, $line, 2);
}

对于@lines = ("11\t1\n", " 22 \t 2 \n", "33\t3");的输入,它给了我@a = (6, 66)

我建议你使用我的答案的拆分部分,但不是添加部分。使用多条线路没有错!如果它使你的意图更清晰,那么更多的线条优于一条线条。但是现在我不再使用perl而是使用python,所以我的perl编码风格可能会产生“坏”的影响......

答案 2 :(得分:2)

很有可能在每次添加时交换该对,这意味着您总是在每对中添加相同的元素。 (如果需要,这可以推广用于旋转多元素阵列。)

use strict;
use warnings;

my @pair = (0, 0);

while (<DATA>) {
  @pair = ($pair[1], $pair[0] + $_) for /\d+/g;
}

print "@pair\n";

__DATA__
99 42
12 15
18 14

<强>输出

129 71

答案 3 :(得分:0)

这是另一种选择:

use Modern::Perl;

my $i = my $j = 0;

map{$i += $_->[0]; $j += $_->[1]} [split] for <DATA>;

say "$i - $j";

__DATA__
1   2
3   4
5   6
7   8

输出:

16 - 20