2014-01-15 33 views
0

我想合併兩個文件(其中一個是分隔空間,劃定的其他選項卡)只保留那些在兩個文件之間的匹配記錄:在Linux中:合併兩個非常大的文件

文件1:空格分隔

A B C D E F G H 
s e id_234 4 t 5 7 9 
r d id_45 6 h 3 9 10 
f w id_56 2 y 7 3 0 
s f id_67 2 y 10 3 0 

文件2:製表符分隔

I L M N O P 
s e 4 u id_67 88 
d a 5 d id_33 67 
g r 1 o id_45 89 

我想匹配文件1場3( 「C」)與文件2字段5( 「O」),併合並這樣的文件:

文件3:製表符分隔

I L M N O P A B D E F G H 
s e 4 u id_67 88 s f 2 y 10 3 0 
g r 1 o id_45 89 r d 6 h 3 9 10 

有文件1,不會出現在文件2,反之亦然條目,但我只想要保持路口(普通IDS)。

我真的不關心順序。

我寧願不使用加入,因爲這些都是非常大的未排序文件和連接需要通過前場常見的,這需要很長的時間和很大的內存來進行排序。

我曾嘗試使用awk,但沒有成功

awk > file3 'NR == FNR { 
    f2[$3] = $2; next 
} 
$5 in f2 { 
print $0, f2[$2] 
}' file2 file1 

有人可以幫我嗎?

非常感謝您

回答

2

嗯..你最好尋找避免在n^2的解決方案,是基於awk的做法似乎有什麼要求。對於file1中的每個記錄,您必須掃描file2以查看是否發生。這就是時間到的地方。

我建議寫這一個Python(或類似)的腳本和構建地圖ID->文件位置中的一個文件,然後查詢,雖然掃描其他文件。這會得到你的nlogn運行它,至少對我來說,看起來是你可以在這裏做的最好(使用散列索引留給你定位到文件pos的看病貴的問題)。

事實上,這裏的Python腳本來做到這一點:

f1 = file("file1.txt") 

f1_index = {} 

# Generate index for file1 
fpos = f1.tell() 
line = f1.readline() 
while line: 
    id = line.split()[2] 
    f1_index[id] = fpos 
    fpos = f1.tell() 
    line = f1.readline() 

# Now scan file2 and output matches 
f2 = file("file2.txt") 
line = f2.readline() 
while line: 
    id = line.split()[4] 
    if id in f1_index: 
     # Found a matching line, seek to file1 pos and read 
     # the line back in 
     f1.seek(f1_index[id], 0) 
     line2 = f1.readline().split() 
     del line2[2] # <- Remove the redundant id_XX 
     new_line = "\t".join(line.strip().split() + line2) 
     print new_line 
    line = f2.readline() 
+0

非常感謝你。由於文件非常大,Python似乎過於緩慢:運行您編寫的腳本需要大約10分鐘的時間(無論如何都要感謝)。我想知道是否有更快的方法來做到這一點? Bash會一樣嗎? – user2337032

+0

在嘗試其他Linux命令以後,在Python中這樣做的解決方案似乎是最好的。我現在纔開始瞭解Python,現在我有一個非常基本的問題:我得到我認爲合併的文件(我猜這是無關緊要的,如果一個是選項卡和其他空間分隔),但標題消失。有沒有辦法保留這兩個文件的頭文件?再次感謝你! – user2337032

+0

如果您的標題是「I L M N O P A B D E F G H」,那麼只需在腳本的頂部添加:print「I L M N O P A B D E F G H」。關於如何加快速度...這完全是關於I/O子系統的最大化,目前的解決方案在這方面是非最優的,因爲它在每條讀取線處停止/啓動。 – tobe

0

如果排序兩個文件(你想匹配的列)是一種可能性(而不會以某種方式打破內容) ,join可能比試圖與bashawk做到這一點的更好方法。既然你聲明你並不關心訂單,那麼這可能是一個合適的方法。

這將是這個樣子:

加入-1 3 -2 5 -O「2.1,2.2,2.3,2.4,2.5,2.6,1.1,1.2,1.4,1.5,1.6,1.7,1.8 '<(sort -k3,3 file1)<(sort -k5,5 file2)

我希望有一個更好的方法來告訴它輸出哪些列,因爲這是很多輸入,但這就是它的方式作品。你也許還留下斷-o ...的東西,然後就後處理的輸出與awk或東西讓它進入你想要的順序...

+0

您好twalberg,謝謝,我寧願避免「加入」,因爲我在問題中說,因爲他們是巨大的未分類文件,如果我使用加入,我將不得不排序他們,它需要太長時間...我希望可以有一個快速的選擇? – user2337032