Ich habe zwei Dateien mit Milliarden von DNA-Sequenznamen, die zweite ist eine echte Teilmenge der ersten:
Zum Beispiel,
1°:john mike anna paul laura ....
2°:john mike paul ...
Alle Namen belegen eine einzelne Zeile.
Meine Frage ist nun: Wie kann ich die Namen abrufen, die in der ersten Datei enthalten sind und in der zweiten nicht?
danke euch allen!
Antwort1
Das ist ganz einfach, aber Ihr Leben wird viel einfacher, wenn Sie einen Namen pro Zeile haben, statt einer durch Leerzeichen getrennten Liste. Es gibt viele hervorragende Dienstprogramme zum Bearbeiten von Textdateien in Linux. Dies ist eine der Sachen, die alle *nixes hervorragend können, aber die meisten erwarten ein Element pro Zeile. Daher beginnen die meisten meiner Lösungen damit, die Dateien entsprechend zu ändern.
Ändern Sie Ihre Dateien so, dass sie pro Zeile einen Namen haben:
sed 's/ /\n/g' file > newfile
oder, um die Originaldatei zu ändern
sed -i 's/ /\n/g' file
Sobald Sie das getan haben, erhalten Sie mit jeder dieser Optionen das gewünschte Ergebnis:
grep
$ grep -vFwf file2 file1 anna laura
comm
oderdiff
$ 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
$ perl -lne 'BEGIN{open(A,"file2"); while(<A>){chomp; $k{$_}++}} print unless $k{$_}' file2 file1 laura anna
oder
$ perl -lne '$k{$_}++; END{map{print unless $k{$_}>1}keys(%k)}' file2 file1 laura anna
Wenn Sie das Format Ihrer Datei wirklich nicht ändern möchten (aber das sollten Sie wirklich), können Sie Folgendes tun:
awk '{for (i=1;i<=NF;i++){a[$i]++}}END{for(n in a){if(a[n]<2){print n}}}' file2 file1
oder
perl -lane '$k{$_}++ for @F; END{map{print if $k{$_}<2} keys(%k)}' file1 file2
Antwort2
Wenn sie sortiert und durch Zeilenumbrüche getrennt sind, können Sie comm
die Zeilen anzeigen, die für Datei1 eindeutig sind:
comm -23 file1 file2
Eine Demonstration:
$ comm -23 <(echo -e 'john\nmike\nanna\npaul\nlaura'|sort) <(echo -e 'john\nmike\npaul'|sort)
anna
laura
Oder Sie könnten diff
so ziemlich dasselbe tun (es grep
wird nach Zeilenlöschungen gesucht):
diff sorted-file-1 sorted-file-2 | grep -oP '(?<=< ).+'
Wenn Sie das Sortieren vermeiden müssen oder mit großen Zahlen arbeiten, würde ich für wörterbuchbasierte Nachschlagevorgänge auf eine geeignete Sprache zurückgreifen. Einfaches Python-Beispiel:
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
Bei allem, was größer ist, sollten Sie sich eine echte Datenbank und einfaches SQL ansehen. Diese sind auf große Datenmengen ausgerichtet.
Antwort3
Und die Python-Option: unabhängig davon, ob alle Wörter in einer Zeile oder auf separaten Zeilen stehen:
#!/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)
Kopieren Sie das Skript in eine leere Datei, speichern Sie es, showdiff.py
machen Sie es ausführbar und führen Sie es mit dem folgenden Befehl aus:
/path/to/showdiff.py file1 file2
anna
laura
Notiz
Das ist zwar nicht die Frage, aber es hängt zu viel damit zusammen, um es wegzulassen:
Wenn Sie die Unterschiede auflisten möchtengegenseitig, (nicht nur Wörter in , file1
die nicht in vorkommen file2
, sondern auch Wörter in file2
, die nicht in vorkommen file1
), Das folgende Skript sollte verwendet werden:
#!/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)
Antwort4
Wenn Sie die Python-Option wählen, wie von Jacob Vlijm vorgeschlagen, lohnt es sich, das 'set' zu verwenden (weitere Informationen finden Sie unterhttps://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset). Sobald Sie die beiden Mengen erstellt haben, können Sie grundsätzlich Mengenmathematik (Vereinigung, Schnittmenge, Differenz usw.) durchführen.
In diesem Fall ist die Differenzmenge genau das, was Sie benötigen: eine neue Menge mit allen Elementen, die in einer Menge enthalten sind und nicht in der anderen.
Der Code von Jacob wäre dann:
#!/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)
Natürlich wird es bei Milliarden von Datensätzen eine Weile dauern …“