2016-03-13 73 views
0

我有一個代碼將所有文件中的所有向量相加。 可以有任意數量的輸入文件。例如第一個輸入文件是:如何識別n個文件中的第n行<>

0.55  0  0.3335  1.2 
0.212  0  2.2025  1 

,第二個是:

0.25  0  0.3333  1.0 
0.1235  0  0.2454  1 

我所得到的是所有矢量的總和,從而在結果我得到一個矢量 ,其是:

1.13550  0  3.1147  4.2 

但我試圖總結第一個文件的第一個向量與第二個文件的第一個向量,依此類推。根據這個例子的結果,我應該得到2個向量。

現在我有這樣的:

use strict; 
use warnings; 

if ($ARGV[0] ne "vector1.dat"){ 
    die ("vector1.dat is necessary as first argument"); 
} 

my @sum = 0; 
my $dim = 0; 

while (<>) { 

    #Ignore blank lines, hashtags 
    #and lines starting with $ 
    if ($_ =~ /#/ || $_ =~ /^$/ || $_ =~ /^\s$/){ 
     next; 
    } 
    my @vectors = split(" ", $_); 
    my $vector_length = @vectors; 

    if ($dim eq 0) { 
     $dim = $vector_length; 
    } 
    else { 
     if ($dim ne $vector_length) { 
      die ("Vector dimensions do not match. : $!"); 
     } 
    } 
    for (my $i = 0; $i <= $#vectors; $i++) { 
     $sum[$i] += $vectors[$i]; 
    } 
} 

$" = "\t\t"; 
print "\n --- \n @sum \n"; 

我需要的就是找出如何識別每個文件的第n行 和總結這些行的列值,同時牢記,有能是n個文件。 我看到文件處理問題在這裏與類似的問題,但 我沒有在那裏找到我的答案。 只是尋找一些建議和指導。卡住了這個。

+0

您應該在shebang行上使用'warning'all''優先於'-w'。不要同時使用 – Borodin

+0

'my @sum = 0'?這是什麼意思?第一個元素爲0的數組? – TLP

+0

如果您打算使用'/^$ /'來檢查以美元符號'$'開頭的行,那麼這將不起作用,因爲'$'是一個正則表達式元字符。你在下一個正則表達式中偶然顯示的內容。 – TLP

回答

2

打開每個文件自己和使用$.變量知道哪一行,你上(或計數的文件自己)。這裏的基本結構:

foreach my $file (@files) { 
    open my $fh, '<', $file or die ...; 
    while(<$fh>) { 
     chomp; 
     $sum[ $. ] = ...; # $. is the line number 
     } 
    } 

如果你不喜歡$.,你可以用它的長名字。你必須打開English(附帶的Perl):

use English; 
## use English qw(-no_match_vars); # for v5.16 and earlier 

foreach my $file (@files) { 
    open my $fh, '<', $file or die ...; 
    while(<$fh>) { 
     chomp; 
     $sum[ $INPUT_LINE_NUMBER ] = ...; 
     } 
    } 

或者,你可以(也許是因爲自己算,如果這些文件中的載體不嚴格的行號排隊,這可能是很方便評論或一些其他格式怪胎):

foreach my $file (@files) { 
    open my $fh, '<', $file or die ...; 
    my $line = -1; 
    while(<$fh>) { 
     $line++; 
     chomp; 
     $sum[ $line ] = ...; 
     } 
    } 

更難的方法是the answer bart gives其中每行的末尾檢查eof,看看神奇ARGV手柄尋找一個新的文件,並重置$.,如果它是。這是一個有趣的技巧,但幾乎沒有人會明白它在做什麼(或者甚至注意到它)。

對於問題的其他部分,我認爲你做的矢量和錯了,或者使用了混淆的變量名。線是矢量,線中的數字是一個組件。一個二維數組將起作用。第一指標是行號和所述第二組件中的索引:

while(<$fh>) { 
    chomp; 
    ... skip unwanted lines 
    my @components = split; 
    ... various dimension checks 
    foreach my $i (0 .. $#components) { 
     $sum[ $. ][ $i ] += $components[ $i ]; 
     } 
    } 

Data::Dumper模塊是非常方便的複雜的數據結構。您還可以看到perldsc(Perl Data Structures Cookbook)文檔。在perlvar中找到$.變量。

+0

謝謝你,你的解釋給了我很多幫助。 完全沒有想到一個二維陣列,這是一個很好的通知 。 – user2961021

+0

如果'$ _'僅用於split('',$ _)',則不需要'chomp($ _)'。 – ikegami

+0

重新「但幾乎沒有人會明白」,這是評論的意思。 – ikegami

-1

試試這個:

#!/usr/bin/perl 
use strict; 
use warnings; 

if ($ARGV[0] ne "vector1.dat"){ 
    die ("vector1.dat is necessary as first argument"); 
} 

my %sum; 
my $dim = 0; 
my $vector_length; 
my $line_number; 

while (<>) { 

    #Ignore blank lines, hashtags 
    #and lines starting with $ 
    if ($_ =~ /#/ || $_ =~ /^$/ || $_ =~ /^\s$/){ 
     next; 
    } 
    my @vectors = split(" ", $_); 
    $vector_length = @vectors; 

    if ($dim eq 0) { 
     $dim = $vector_length; 
    } 
    else { 
     if ($dim ne $vector_length) { 
      die ("Vector dimensions do not match. : $!"); 
     } 
    } 
    for (my $i = 0; $i <= $#vectors; $i++) { 
     $sum{$.}{$i} += $vectors[$i]; 
    } 
    $line_number = $.; 
    $. = 0 if eof; 
} 

$" = "\t\t"; 
for (my $line=1; $line<=$line_number; $line++) 
{ 
    print $line; 
    for (my $vector=0; $vector<$vector_length; $vector++) 
    { 
     print " " . $sum{$line}{$vector}; 
    } 
    print "\n"; 
} 
+3

「試試這個」答案沒有進一步的解釋是相當煩人的,並不是很有價值。這意味着我必須通讀你的整個代碼,看看它與OP有什麼不同,並嘗試辨別你正在嘗試做什麼,以及如果你做得對。 – TLP

+0

'close(ARGV)if eof;'是記錄的例子。 – ikegami

+0

如果最後一行是空白或註釋,則不起作用。 – ikegami

0

$.是最近讀取的文件句柄的行號。close(ARGV) if eof;可用於重置文件之間的文件編號(如eof中所述)。 (注意:eof()不同於eof。)所以你現在有行號。

您遇到的第二個問題是您要將向量組件($vectors[$i])添加到向量($sum[$i])。您需要將向量組件添加到向量組件。首先使用更合適的變量名稱。

這就是我們得到:固定其他

my @sum_vectors; 
while (<>) { 
    s/#.*//;   # Remove comments. 
    next if /^\s*$/; # Ignore blank lines. 

    my @vector = split; 

    if ($sum_vectors[$.] && @{ $sum_vectors[$.] } != @vector) { 
     die("$ARGV:$.: Vector dimensions do not match\n"); 
    } 

    for my $i (0..$#vector) { 
     $sum_vectors[$.][$i] += $vector[$i]; 
    } 
} continue { 
    close(ARGV) if eof; # Reset line numbers for each file. 
} 

兩個錯誤:

  • $!不包含任何有意義的東西,當你使用它。
  • 您忽略了包含註釋的行,即使它們也包含有效數據。
+0

當聲明變量時,我會更具體一些,抱歉讓名字不恰當的讀者感到困惑。 – user2961021

+0

不是這樣。選擇合適的名稱以避免混淆*自己*很重要。用我使用的名字,你不正確的加法('$ sum_vectors [$ i] + = $ vector [$ i];')看起來不正確。你本可以自己說出一些錯誤。 – ikegami

+0

的確如此。將小心與namings。是的,我已經注意到了無用的$!也是可變的。至於評論,這是一個非常好的觀點。感謝你的幫助,你讓我注意到了我錯過的非常簡單但重要的事情。 – user2961021

相關問題