2012-05-23 50 views
3

我想逐行解析一個文件,每個文件都包含兩個整數,然後將這些值求和成兩個不同的變量。我天真的做法是這樣的:如何將兩個列表按元素求和

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

但它產生以下警告:

在無效的情況下

沒用使用私有變量的暗示訴諸+ =操作觸發器以標量而不是列表上下文評估左側(如果我在這一點上錯誤,請糾正我)。

是否有可能實現這個優雅(可能在一行)而不訴諸數組或中間變量?


相關問題:How can I sum arrays element-wise in Perl?

回答

6

不,這是因爲表達($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; 
} 

您可以通過使用複合數據結構而不是命名變量爲列避免重複。

+1

你是什麼你的最後一句話是什麼意思?例如,一個兩元素數組仍然需要單獨的算術語句,除非您正在考慮重載'+ ='? – Borodin

+0

簡單來說就像kratenko的答案中的數組。那 - 加上無限制的分割 - 適用於任意數量的列。 – daxim

+0

+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的,但蟒蛇代替,讓我的Perl編程風格可能有一個「壞」的影響力有...

+2

這個'map'表達式是非常強大的Perl,對於這個意圖沒有什麼不清楚的。 +1 – daxim

+1

@daxim Hej,所以今天我學到了一個新詞,_cromulent_。感謝您融入我的詞彙。 – kratenko

+0

'split'調用中的限制2假定每個記錄只有兩個字段。否則,你會得到'(field1,rest-of-record)'。即使只有兩個字段,它幾乎沒有意義,並且也會將換行符留在第二個字段的末尾。 – Borodin

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 
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 
+0

+1清晰簡潔的解決方案 –

相關問題