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