2014-03-06 72 views
4

我有一個製表符分隔的文件,該文件是這樣的:我在尋找一個如何打印第1列的第一行,並基於該uique標識列第二列的最後一行3

Het 157709 157731 Cluster.90 2 + 
Het 157739 157760 Cluster.90 2 + 
Het 164238 164259 Cluster.97 10 + 
Het 164380 164401 Cluster.97 10 + 
Het 164396 164417 Cluster.97 10 + 
Het 164397 164421 Cluster.97 10 + 
Het 164397 164420 Cluster.97 10 + 
Het 164399 164420 Cluster.97 10 + 
Het 164536 164561 Cluster.97 10 + 
Het 164576 164598 Cluster.97 10 + 
Het 164599 164615 Cluster.97 10 + 
Het 164635 164656 Cluster.97 10 + 
Het 198007 198031 Cluster.125 3 + 
Het 198007 198028 Cluster.125 3 + 
Het 198011 198035 Cluster.125 3 + 

Het 157709 157760 Cluster.90 2 + 
Het 164238 164656 Cluster.97 10 + 
Het 198007 198035 Cluster.125 3 + 

凡在塔4每個獨特條目,我寫一個系列,其包括在第3欄爲隨後的最後一行列1和2的第一行,4:以產生如下所示的文件有效的方式,5和6.到目前爲止,我已經嘗試了以下解決方案,但它看起來效率很低:

for i in `awk '{print $4}' filename | sort | uniq` 
    do 
    fgrep -F $i -w filename | awk 'NR==1 {printf $1"\t"$2"\t"} END {print $3"\t"$4"\t"$5"\t"$6}' >>filename2 
done 

問題是,當我有一個巨大的文件(487559行),這需要永遠。有沒有更好的解決方案藏在別人的腦海裏?

回答

1

這可以在單一AWK來完成,這將是比你的腳本更有效:

awk '!($4 in a){a[$4]=$1 FS $2; r[++i]=$4; b[$4]=$3 FS $4 FS $5 FS $6; next;} {b[$4]=$3 FS $4 FS $5 FS $6; next} END{for (k=1; k<=i; k++) print a[r[k]], b[r[k]]}' OFS='\t' file 
Het 157709  157760 Cluster.90 2 + 
Het 164238  164656 Cluster.97 10 + 
Het 198007  198035 Cluster.125 3 + 

要使其可讀:

awk '!($4 in a){ 
    a[$4]=$1 FS $2; 
    r[++i]=$4; 
    b[$4]=$3 FS $4 FS $5 FS $6; 
    next; 
} 
{ 
    b[$4]=$3 FS $4 FS $5 FS $6; 
    next; 
} 
END { 
    for (k=1; k<=i; k++) 
     print a[r[k]], b[r[k]] 
}' OFS='\t' file 
+0

有點縮短:'AWK」($ 4以){A [$ 4] = $ 1 FS $ 2; r [++ i] = $ 4;} {b [$ 4] = $ 3 FS $ 4 FS $ 5 FS $ 6;} END {for(k = 1; k <= i; k ++)print a [r [k]],b [r [k]]}'OFS ='\ t'文件'。但它仍然是不必要的RAM飢餓 – rici

0

你的代碼是緩慢的,因爲你發射了fgrep和每個組的awk進程。

您可以簡單地在第4列進行排序後一次處理整個文件,當然,您已經知道該如何操作。

所以,只需在bash,python,ruby,perl,awk或您選擇的任何語言中從stdin逐行讀取,並在第4列中記錄最後一次看到的值。只要此值發生更改,就可以執行所需操作要做的是:寫出包含前兩列中的第一個看到的值和後面的列中最後看到的值的行。然後記錄第1列和第2列的新值。它非常簡單,但在第一行和最後一行可能會非常棘手。

3

如果第4列中的唯一條目在第5列中始終具有相同的數據,則此一行將僅起作用。你的例子就是這樣,但在我看來並沒有真正回答這個問題。儘管如此,FWIW:

paste <(uniq -f3 file | cut -f1,2) <(tac file | uniq -f3 | tac | cut -f3-) 

uniq具有控制字符數來比較獨特的選項,以及領先的字段跳過的數量和前導字符跳過數,而不是數量的領域進行比較。

1

下面是另一種方式與awk

awk ' 
!seen[$4]++ { 
    col[$4] = $1 FS $2; 
    fld[++i] = col[$4] 
} 
{ 
    sub(/([^ ]+ +){2}/,x); 
    line[i] = fld[i] FS $0 
} 
END { 
    for(x = 1; x <= i; x++) 
    print line[x] 
}' OFS='\t' file 

輸出:

Het 157709 157760 Cluster.90 2 + 
Het 164238 164656 Cluster.97 10 + 
Het 198007 198035 Cluster.125 3 + 
相關問題