2012-06-08 26 views
2

關鍵變化我有以下格式輸入文件合計不等時在Perl

ant,1 
bat,1 
bat,2 
cat,4 
cat,1 
cat,2 
dog,4 

我需要聚合的COL2每個鍵(列1),所以其結果是:

ant,1 
bat,3 
cat,7 
dog,4 

其他注意事項:

  1. 假定輸入文件排序
  2. 釷Ë輸入文件相當大(約100萬行),所以我不想使用數組和佔用內存
  3. 當我們讀它的每個輸入行應該進行處理,並移動到下一行
  4. 我需要將結果寫入到一個不過outFile
  5. 我必須這樣做在Perl,但僞代碼或算法將幫助剛剛精細

謝謝!

這就是我想出的...想看看這是否可以寫得更好/優雅。

open infile, outFile 

prev_line = <infile>; 
print_line = $prev_line; 

while(<>){ 
    curr_line = $_; 

    @prev_cols=split(',', $prev_line); 
    @curr_cols=split(',', $curr_line); 

    if ($prev_cols[0] eq $curr_cols[0]){ 
     $prev_cols[1] += curr_cols[1]; 
     $print_line = "$prev_cols[0],$prev_cols[1]\n"; 
     $print_flag = 0; 
    } 
    else{ 
     $print outFile "$print_line"; 
     $print_flag = 1; 
     $print_line = $curr_line; 
    } 
    $prev_line = $curr_line; 
} 

if($print_flag = 1){ 
    print outFile "$curr_line"; 
} 
else{ 
    print outFile "$print_line"; 
} 
+0

作業多嗎? – DVK

回答

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

my %a; 
while (<>) { 
    my ($animal, $n) = /^\s*(\S+)\s*,\s*(\S+)/; 
    $a{$animal} += $n if defined $n; 
} 
print "$_,${a{$_}}\n" for sort keys %a; 

這個簡短的代碼,給您學習Perl的出色的哈希設施,爲%a的機會。哈希是Perl的核心。沒有它們,真的不能寫流利的Perl。

觀察偶然的代碼行使Perl的有趣自動激活功能。輸入流中第一次遇到特定的動物時,不存在計數,所以Perl隱含地假定預先存在的計數爲零。因此,+=運營商不會失敗,即使它似乎應該。它首先增加到零。

另一方面,可能發生的情況不僅是數據的數量,而且的動物數量太大,以至於不想存儲散列%a。在這種情況下,仍然可以計算總數,只要數據按輸入中的動物排序即可,如同您的示例中所示。在這種情況下,像下面這樣的東西可能會適合(雖然令人遺憾的是它並不像上面那麼簡潔)。

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

my $last_animal = undef; 
my $total_for_the_last_animal = 0; 

sub start_new_animal ($$) { 
    my $next_animal = shift; 
    my $n = shift; 
    print "$last_animal,$total_for_the_last_animal\n" 
     if defined $last_animal; 
    $last_animal = $next_animal; 
    $total_for_the_last_animal = $n; 
} 

while (<>) { 
    my ($animal, $n) = /^\s*(\S+)\s*,\s*(\S+)/; 
    if (
     defined($n) && defined($animal) && defined($last_animal) 
      && $animal eq $last_animal 
    ) { $total_for_the_last_animal += $n; } 
    else { start_new_animal $animal, $n; } 
} 
start_new_animal undef, 0; 
+0

非常感謝。這很好。但後來我們把所有的數據加載到內存中(哈希)......對吧?如果我有一個我正在避免加載到內存中的大文件呢?該解決方案非常優雅。我需要了解更多關於Perl哈希的知識。 –

+0

確實哈希爲螞蟻,蝙蝠,貓和狗保留了一個條目。但是,散列只保留一個螞蟻的總運行總數,只有一個運行總數的蝙蝠,等等。它不存儲輸入的每一行。你的應用程序是否會帶來很多*不同種類的動物,即使每隻動物保持一次跑步總數也是不合理的? – thb

+0

是的,唯一鍵的數量將非常大。我不能把所有東西都放在哈希中。對於較小的套件,解決方案將運行良好。 –

0

這在Perl中是微不足道的。在文件輸入上循環。用逗號分割輸入行。對於列中的每個鍵,保留一個哈希值,在第二列中添加該值。在文件的最後打印散列鍵及其值的列表。它可以在一行中完成,但會混淆算法。

1

使用Perl的awk mode

  • -a

-n-p使用時打開自動分割模式。對@F陣列的隱式split命令作爲由-n-p產生的隱式while循環內的第一件事完成。

perl -ane 'print pop(@F), "\n";' 

相當於

while (<>) { 
    @F = split(' '); 
    print pop(@F), "\n"; 
} 

一種替代定界符可以使用-F指定。

所有剩下的東西就是在一個散列中累加和打印它們。

$ perl -F, -lane '$s{$F[0]} += $F[1]; 
    END { print "$_,$s{$_}" for sort keys %s }' input 

輸出:

ant,1 
bat,3 
cat,7 
dog,4
+0

謝謝Greg。但我的限制是,我的輸入文件將是巨大的,我不想使用散列,因爲會有太多的唯一鍵。所以,我需要處理每一行的內容......也就是說,如果下一個關鍵字不同,則打印它,或者如果關鍵字相同,則將其聚合。請評論我的代碼。謝謝! –