3

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

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

但它会产生以下警告:

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

暗示诉诸 += 运算符会触发以标量而不是列表上下文对左侧进行评估(如果我在这一点上错了,请纠正我)。

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


相关问题:如何在 Perl 中按元素对数组求和?

4

4 回答 4

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;
}

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

于 2012-05-23T10:15:46.937 回答
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 编码风格可能会在那里产生“坏”的影响......

于 2012-05-23T10:37:24.440 回答
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
于 2012-05-23T13:42:06.743 回答
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
于 2012-05-23T12:52:01.447 回答