Ich habe eine CSV-Datei users.csv
mit einer Liste von Benutzernamen, Benutzer-IDs und anderen Daten:
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"Paul McCartny", 30923833, "left", "black"
"Ringo Starr", 77392318, "right", "blue"
"George Harrison", 72349482, "left", "green"
In einer anderen Datei habe toremove.txt
ich eine Liste von Benutzer-IDs:
30923833
77392318
Gibt es eine clevere und effiziente Möglichkeit, alle Zeilen aus der users.csv
Datei zu entfernen, in der sich die IDs befinden toremove.txt
? Ich habe eine einfache Python-App geschrieben, um die beiden Dateien zu analysieren und in eine neue Datei nur die Zeilen zu schreiben, in denen sie nicht gefunden werden toremove.txt
, aber sie ist außerordentlich langsam. Vielleicht kann etwas sed
oder awk
Magie hier helfen?
Dies ist das gewünschte Ergebnis, wenn man die obigen Beispiele betrachtet:
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
linux
command-line
text-processing
dotancohen
quelle
quelle
users.csv
Zeilen der Datei und n für die Zeilen vontoremove.txt
. Ich bin mir nicht sicher, wie ich es mit geringer Komplexität machen soll. Der Kern ist:for u in users: if not any(toremove in u): outputfile.write(u)
. Ich kann es bei Code Review posten.toremove.txt
und die Einträge als Schlüssel speichern . Iterieren Sie users.csv und geben Sie diejenigen aus, bei denen die ID nicht im Diktat enthalten ist. Sie erhalten O (n) Verarbeitung für beidetoremove.txt
undusers.csv
, und O (n) Speichernutzung fürtoremove.txt
(was wahrscheinlich ist relativ klein)Antworten:
Mit
grep
können Sie:Mit
awk
:quelle
awk
Lösung reagiert sehr empfindlich darauf, dass die Dateien genau wie in der Frage gezeigt formatiert werden . Am augenfälligsten ist es, wenn ein Name nur ein Wort / Token ist (dh, er enthält keine Leerzeichen; z. B."Bono"
) oder mehr als zwei Token (dh, er enthält mehr als ein Leerzeichen; z. B."Sir Paul McCartney"
), selbst wenn das durchlaufen wird Benutzer-ID-Übereinstimmungen. Weniger offensichtlich passiert dasselbe, wenn zwischen dem ersten Komma und der Benutzer-ID kein Leerzeichen ist oder wenn mehr als ein Leerzeichen (z"John Lennon", 90123412, …
. B. ) vorhanden ist.awk
Lösung hinter mich gebracht habegrep
Hier ist Gnoucs
awk
Antwort:Da es nur Kommas (und keine Leerzeichen) als Begrenzer verwendet,
$1
ist"John Lennon"
,$2
ist90123412
(mit einem führenden Leerzeichen) usw. Dahergensub
entfernen wir eine beliebige Anzahl führender Leerzeichen,$2
bevor wir prüfen, ob es (die Benutzer-ID) in dertoremove.txt
Datei war.quelle
OK ein Rubin Art und Weise: wenn Sie eine Liste von Zeichenkette in einer Datei, und Sie alle Zeilen aus einer anderen Datei zu entfernen , dass auch enthält eine beliebige Zeichenfolge in der ersten Datei (in diesem Fall „file2“ von „file1“ zu entfernen) Rubin - Datei :
Leider scheint dies bei einer großen "zu entfernenden" Datei die Komplexität auf O (N ^ 2) herabzusetzen (meine Vermutung ist, dass RegExp eine Menge Arbeit zu erledigen hat), könnte aber dennoch für jemanden da draußen nützlich sein (falls Sie dies tun) wollen mehr als das Entfernen ganzer Zeilen). In bestimmten Fällen kann es schneller sein.
Eine andere Möglichkeit, wenn Sie auf Geschwindigkeit aus sind, besteht darin, denselben Hash-Überprüfungsmechanismus zu verwenden, die Zeile jedoch sorgfältig nach möglicherweise übereinstimmenden Zeichenfolgen zu "parsen" und sie dann mit Ihrem Hash zu vergleichen.
In Ruby könnte das so aussehen:
Siehe auch Scotts Antwort, die den hier vorgeschlagenen awk-Antworten ähnlich ist, und vermeidet die Komplexität von O (N ^ 2) (puh).
quelle