Perl 如何按元素对两个列表求和

Perl 如何按元素对两个列表求和,perl,list,Perl,List,我想逐行解析一个文件,每个文件包含两个整数,然后在两个不同的变量中求和这些值。我天真的做法是这样的: my $i = 0; my $j = 0; foreach my $line (<INFILE>) { ($i, $j) += ($line =~ /(\d+)\t(\d+)/); } my$i=0; 我的$j=0; foreach我的$line() { ($i,$j)+=($line=~/(\d+)\t(\d+)/); } 但它产生了以下警告: 在void上下文中无用地

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

my $i = 0;
my $j = 0;
foreach my $line (<INFILE>)
{
    ($i, $j) += ($line =~ /(\d+)\t(\d+)/);
}
my$i=0;
我的$j=0;
foreach我的$line()
{
($i,$j)+=($line=~/(\d+)\t(\d+)/);
}
但它产生了以下警告:

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

暗示诉诸+=运算符会触发标量而不是列表上下文中左侧的求值(如果我在这一点上错了,请纠正我)

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



相关问题:

不,这是因为表达式
($i,$j)+=(something,1)
解析为只将
1
添加到
$j
中,而将
$i
挂在无效上下文中。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;
}
my($i,$j)=(0,0);
foreach我的$line(){
my($this_i,$this_j)=拆分/\t/,$line;
$i+=$this\u i;
$j+=$this_j;
}

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

首先,您两两添加数组的方法不起作用(您自己发布的相关问题给出了一些提示)

对于解析部分:如何拆分行?如果您的行被相应地格式化(空格应该不是问题)

如果你真的,真的想在一行中完成,你可以这样做(尽管我不认为你会称之为优雅):

my@a=(0,0);
foreach我的$line()
{
@a=映射{shift(@a)+${split(/\t/,$line,2);
}
对于
@lines=(“11\t1\n”、“22\t2\n”、“33\t3”)的输入它给了我
@a=(6,66)

我建议你使用我答案的拆分部分,而不是累加部分。使用多行代码没有什么错!如果能让你的意图更清晰,多行比一行好。但是现在我几乎不使用perl,而是使用python,因此我的perl编码风格可能会产生“坏”影响…

这里有另一个选择:

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

对于每一个加法,都可以交换一对,这意味着您总是在每一对中添加相同的元素。(如果需要,这将推广到旋转多元素阵列。)

使用严格;
使用警告;
我的@pair=(0,0);
而(){
@pair=($pair[1],$pair[0]+$\表示/\d+/g;
}
打印“@pair\n”;
__资料__
99 42
12 15
18 14
输出

12971

这个
map
表达式完全是由Perl编写的,其意图并不清楚+1@daxim嘿,所以我今天学了一个新单词,克罗姆伦。感谢您扩充我的词汇表。
split
调用中2的限制假定每条记录只有两个字段。否则您将得到
(字段1,记录的其余部分)
。即使只有两个字段,它也毫无意义,并且在第二个字段的末尾保留换行符。@borodin结尾的换行符应该不会有问题(在我尝试它时工作)。但好的一点是,应该可以使它适用于任何(恒定)数量的列。当我回到自己的电脑前,我会试试的。分割部分+1。我完全同意你的“如果它能让你的意图更清晰,多行比一行好”你最后一句话是什么意思?例如,一个两元素数组仍然需要单独的算术语句,除非您考虑重载
+=
?就像kratenko答案中的数组一样。这与无限制拆分相结合,适用于任意数量的列。
my @a = (0, 0);
foreach my $line (<INFILE>)
{
    @a = map { shift(@a)+$_ } split(/\t/, $line, 2);
}
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