Tengo un archivo CSV users.csvcon 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.txttengo una lista de ID de usuario:
30923833
77392318
¿Existe una manera inteligente y eficiente de eliminar todas las filas del users.csvarchivo 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 sedo awkmagia 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.csvlí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.txtyusers.csv, y el uso de memoria O (n) paratoremove.txt(que probablemente sea relativamente pequeño)Respuestas:
Con
grep, puedes hacer:Con
awk:fuente
awksolució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, …).awksolución detrásgrepAquí está la
awkrespuesta de Gnouc , modificada para ser ciega al espacio:Dado que usa solo comas (y no espacios) como delimitadores,
$1es"John Lennon",$2es90123412(con un espacio inicial), etc. Por lo tanto, usamosgensubpara eliminar cualquier número de espacios iniciales$2antes de verificar si (el ID de usuario) estaba en eltoremove.txtarchivo.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