Tengo un archivo CSV users.csv
con una lista de nombres de usuario, ID de usuario y otros datos:
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"
En otro archivo toremove.txt
tengo una lista de ID de usuario:
30923833
77392318
¿Existe una manera inteligente y eficiente de eliminar todas las filas del users.csv
archivo que contienen los ID toremove.txt
? He escrito una aplicación simple de Python para analizar los dos archivos y escribir en un nuevo archivo solo aquellas líneas que no se encuentran toremove.txt
, pero es extraordinariamente lenta. Tal vez algo sed
o awk
magia puede ayudar aquí?
Este es el resultado deseado, considerando los ejemplos anteriores:
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
linux
command-line
text-processing
dotancohen
fuente
fuente
users.csv
líneas del archivo yn para las líneas detoremove.txt
. No estoy realmente seguro de cómo hacerlo con menor complejidad. El quid de la cuestión es:for u in users: if not any(toremove in u): outputfile.write(u)
. Puedo publicarlo en Code Review.toremove.txt
, guardando las entradas como claves . Iterate users.csv, imprimiendo aquellos donde la identificación no está en el dict. Obtiene el procesamiento O (n) para ambostoremove.txt
yusers.csv
, y el uso de memoria O (n) paratoremove.txt
(que probablemente sea relativamente pequeño)Respuestas:
Con
grep
, puedes hacer:Con
awk
:fuente
awk
solución es muy sensible a los archivos que se formatean exactamente como se muestra en la pregunta. Lo más evidente es que si un nombre es solo una palabra / ficha (es decir, no contiene espacios; por ejemplo"Bono"
) o si tiene más de dos fichas (es decir, contiene más de un espacio; por ejemplo"Sir Paul McCartney"
), pasará incluso si el coincidencias de ID de usuario. Menos obvio, lo mismo sucede si no hay espacio entre la primera coma y el ID de usuario, o si hay más de un espacio (por ejemplo,"John Lennon", 90123412, …
).awk
solución detrásgrep
Aquí está la
awk
respuesta de Gnouc , modificada para ser ciega al espacio:Dado que usa solo comas (y no espacios) como delimitadores,
$1
es"John Lennon"
,$2
es90123412
(con un espacio inicial), etc. Por lo tanto, usamosgensub
para eliminar cualquier número de espacios iniciales$2
antes de verificar si (el ID de usuario) estaba en eltoremove.txt
archivo.fuente
OK de una manera rubí: si tiene una lista de cadenas en un archivo y desea eliminar todas las líneas de otro archivo que incluso contenga cualquier cadena en el primer archivo (en este caso, eliminar "archivo2" de "archivo1") :
desafortunadamente con un gran archivo "para eliminar", esto parece degradar la complejidad a O (N ^ 2) (supongo que la expresión regular tiene mucho trabajo por hacer), pero aún podría ser útil para alguien por ahí (si usted desea más que eliminar líneas completas). Puede ser más rápido en ciertos casos.
Otra opción si va por la velocidad es usar el mismo mecanismo de comprobación de hash, pero "analizar" cuidadosamente la línea en busca de cadenas que puedan coincidir, y luego compararlas con su hash.
En ruby, podría verse así:
Ver también la respuesta de Scott, es similar a las respuestas awk propuestas aquí, y evita la complejidad O (N ^ 2) (phew).
fuente