Mam plik CSV users.csv
z listą nazw użytkowników, identyfikatorów użytkowników i innych danych:
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"
W innym pliku toremove.txt
mam listę identyfikatorów użytkowników:
30923833
77392318
Czy istnieje sprytny i skuteczny sposób na usunięcie wszystkich wierszy z users.csv
pliku zawierającego identyfikatory toremove.txt
? Napisałem prostą aplikację w języku Python, aby przeanalizować dwa pliki i zapisać w nowym pliku tylko te wiersze, których nie ma toremove.txt
, ale jest to wyjątkowo powolne. Być może trochę sed
lub awk
magia może tu pomóc?
Jest to pożądany wynik, biorąc pod uwagę powyższe przykłady:
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
linux
command-line
text-processing
dotancohen
źródło
źródło
users.csv
pliku i n dla liniitoremove.txt
. Nie jestem pewien, jak to zrobić z mniejszą złożonością. Istotą jest to:for u in users: if not any(toremove in u): outputfile.write(u)
. Mogę wysłać to do recenzji kodu.toremove.txt
, zapisując wpisy jako klucze . Iterate users.csv, drukowanie tych, których identyfikatora nie ma w dykcie. Otrzymujesz przetwarzanie O (n) zarówno dla, jaktoremove.txt
iusers.csv
O (n) użycie pamięci dlatoremove.txt
(co jest prawdopodobnie stosunkowo niewielkie)Odpowiedzi:
Za pomocą
grep
możesz:Z
awk
:źródło
awk
Rozwiązanie jest bardzo wrażliwa na plikach sformatowanych jest dokładnie jak pokazane w pytaniu. Najbardziej rażąco, jeśli nazwa jest tylko jednym słowem / tokenem (tzn. Nie zawiera spacji; np."Bono"
) Lub zawiera więcej niż dwa tokeny (tj. Zawiera więcej niż jedną spację; np."Sir Paul McCartney"
), Przejdzie nawet, jeśli dopasowania identyfikatora użytkownika. Mniej oczywiste, to samo dzieje się, jeśli między pierwszym przecinkiem a identyfikatorem użytkownika nie ma spacji lub jeśli jest więcej niż jedna spacja (np"John Lennon", 90123412, …
.).awk
za sobą rozwiązaniegrep
Oto
awk
odpowiedź Gnouca , zmodyfikowana tak, aby była ślepa na kosmos:Ponieważ używa ograniczników tylko przecinków (a nie spacji),
$1
jest"John Lennon"
,$2
jest90123412
(ze spacją wiodącą) itp. Dlatego używamygensub
do usunięcia dowolnej liczby wiodących spacji$2
przed sprawdzeniem, czy (identyfikator użytkownika) był wtoremove.txt
pliku.źródło
OK w ruby sposób: jeśli masz listę ciągów w pliku i chcesz usunąć wszystkie wiersze z innego pliku, które zawierają nawet dowolny ciąg w pierwszym pliku (w tym przypadku usuwając „plik2” z „pliku1”) plik ruby :
niestety przy dużym pliku „do usunięcia” wydaje się to obniżać złożoność do O (N ^ 2) (moje założenie jest takie, że regexp ma dużo pracy), ale nadal może być przydatne dla kogoś tam (jeśli ty chcesz więcej niż usuwanie pełnych linii). W niektórych przypadkach może być szybszy.
Inną opcją, jeśli dążysz do szybkości, jest użycie tego samego mechanizmu sprawdzania skrótu, ale ostrożne „przeanalizowanie” wiersza w celu dopasowania pasujących ciągów znaków, a następnie porównanie ich ze skrótem.
W rubinie może wyglądać tak:
Zobacz także odpowiedź Scotta, jest podobna do proponowanych tu odpowiedzi na awk i unika złożoności O (N ^ 2) (uff).
źródło