我有兩個文件,其中包含數十億個 DNA 序列名稱,第二個文件是第一個文件的真子集:
例如,
1°:john mike anna paul laura ....
2°:john mike paul ...
所有名稱佔一行。
我的問題是,如何取得第一個文件中包含但第二個文件中不包含的名稱?
謝謝大家!
答案1
這很簡單,但如果每行只有一個名稱而不是空格分隔的列表,您的生活會容易得多。 Linux 中有許多用於操作文字檔案的優秀實用程序,這是所有 *nixes 都擅長的事情之一,但大多數人期望每行一個專案。因此,我的大多數解決方案將從相應地修改文件開始。
將文件更改為每行一個名稱:
sed 's/ /\n/g' file > newfile
或者,修改原始文件
sed -i 's/ /\n/g' file
一旦你這樣做了,其中任何一個都會給你你想要的:
grep
$ grep -vFwf file2 file1 anna laura
comm
或者diff
$ comm -23 <(sort file1) <(sort file2) anna laura $ diff file1 file2 | grep -Po '<\s+\K.*' anna laura
awk
$ awk '(NR==FNR){a[$1]++; next}!($1 in a){print}' file2 file1 laura anna
珀爾
$ perl -lne 'BEGIN{open(A,"file2"); while(<A>){chomp; $k{$_}++}} print unless $k{$_}' file2 file1 laura anna
或者
$ perl -lne '$k{$_}++; END{map{print unless $k{$_}>1}keys(%k)}' file2 file1 laura anna
如果您確實不想更改文件的格式(但實際上您應該這樣做),您可以執行類似的操作
awk '{for (i=1;i<=NF;i++){a[$i]++}}END{for(n in a){if(a[n]<2){print n}}}' file2 file1
或者
perl -lane '$k{$_}++ for @F; END{map{print if $k{$_}<2} keys(%k)}' file1 file2
答案2
如果它們按換行符號排序和分隔,您可以使用comm
顯示 file1 特有的行:
comm -23 file1 file2
演示:
$ comm -23 <(echo -e 'john\nmike\nanna\npaul\nlaura'|sort) <(echo -e 'john\nmike\npaul'|sort)
anna
laura
或者你可以diff
做同樣的事情(grep
正在尋找行刪除):
diff sorted-file-1 sorted-file-2 | grep -oP '(?<=< ).+'
如果您需要避免排序或正在處理嚴重的數字,我會轉向合適的語言來進行基於字典的查找。簡單的Python範例:
file2 = {}
with open("file2") as f:
for line in f:
file2[line] = 0
with open("file1") as f:
for line in f:
if not line in file2:
print line
任何比這更大的東西,你可能想要查看一個實際的資料庫和一些簡單的 SQL。它們適合大數據。
答案3
還有 python 選項:無論所有單字是在一行還是在單獨的行上:
#!/usr/bin/env python3
import sys
f1 = sys.argv[1]; f2 = sys.argv[2]
def read(f):
with open(f) as content:
return content.read().split()
for item in [w for w in read(f1) if not w in read(f2)]:
print(item)
將腳本複製到一個空文件中,將其另存為showdiff.py
使其可執行並透過以下命令運行它:
/path/to/showdiff.py file1 file2
anna
laura
筆記
不是問題,而是聯絡太多,無法遺漏:
如果您需要列出差異相互,(不僅是file1
中 中未出現的單字file2
,而且是file2
中 中未出現的單字file1
),應使用以下腳本:
#!/usr/bin/env python3
import sys
f1 = sys.argv[1]; f2 = sys.argv[2]
def read(f):
with open(f) as content:
return content.read().split()
wds1 = read(f1); wds2 = read(f2); allwords = wds1+wds2
for item in [w for w in allwords if (w in wds1, w in wds2).count(False) == 1]:
print(item)
答案4
如果您按照 Jacob Vlijm 建議使用 python 選項,則值得使用“set”(有關更多信息,請參閱https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset)。基本上,一旦創建了兩個集合,您就可以實現集合數學(並集,交集,差異,...)
在這種情況下,集合差異正是您所需要的:一個包含一組中所有元素的新集合,並且不在另一個。
Jacob 的代碼將是:
#!/usr/bin/env python3
import sys
f1 = sys.argv[1]; f2 = sys.argv[2]
def read_set(f):
with open(f) as content:
return set(content.read().split())
for item in read_set(f1) - read_set(f2)]:
print(item)
當然,對於數十億筆記錄來說,還需要一段時間…`