J'ai un fichier CSV users.csv
avec une liste de UserNames, userIDs et autres données:
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"
Dans un autre fichier, toremove.txt
j'ai une liste d'utilisateurs:
30923833
77392318
Existe-t-il un moyen intelligent et efficace de supprimer toutes les lignes du users.csv
fichier contenant les ID toremove.txt
? J'ai écrit une simple application Python pour analyser les deux fichiers et écrire dans un nouveau fichier uniquement les lignes qui ne se trouvent pas toremove.txt
, mais c'est extrêmement lent. Peut-être que certains sed
ou la awk
magie peuvent aider ici?
C'est le résultat souhaité, compte tenu des exemples ci-dessus:
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"
linux
command-line
text-processing
dotancohen
la source
la source
users.csv
lignes du fichier, et n pour les lignes detoremove.txt
. Je ne sais pas vraiment comment le faire avec une complexité moindre. L'essentiel de c'est:for u in users: if not any(toremove in u): outputfile.write(u)
. Je peux le poster sur Code Review.toremove.txt
en sauvegardant les entrées sous forme de clés . Itérer les utilisateurs.csv, en imprimant ceux dont l'id n'est pas dans le dict. Vous obtenez le traitement O (n) pour les deuxtoremove.txt
etusers.csv
, et l'utilisation de la mémoire O (n) pourtoremove.txt
(qui est probablement relativement petite)Réponses:
Avec
grep
, vous pouvez faire:Avec
awk
:la source
awk
solution est très sensible au formatage des fichiers exactement comme indiqué dans la question. Le plus flagrant, si un nom est juste un mot / jeton (c'est-à-dire qu'il ne contient aucun espace; par exemple,"Bono"
) ou est plus de deux jetons (c'est-à-dire qu'il contient plus d'un espace; par exemple,"Sir Paul McCartney"
), il passera même si le correspond à l'ID utilisateur. Moins évidemment, la même chose se produit s'il n'y a pas d'espace entre la première virgule et l'ID utilisateur, ou s'il y a plus d'un espace (par exemple,"John Lennon", 90123412, …
).awk
solution derrièregrep
Voici la
awk
réponse de Gnouc , modifiée pour être aveugle à l'espace:Puisqu'il n'utilise que des virgules (et non des espaces) comme délimiteurs,
$1
is"John Lennon"
,$2
is90123412
(avec un espace de tête), etc. Nous utilisons doncgensub
pour supprimer n'importe quel nombre d'espaces de tête$2
avant de vérifier s'il (l'ID utilisateur) était dans letoremove.txt
fichier.la source
OK d'une manière rubis: si vous avez une liste de chaînes dans un fichier et que vous souhaitez supprimer toutes les lignes d'un autre fichier qui contiennent même n'importe quelle chaîne dans le premier fichier (dans ce cas, supprimer "fichier2" de "fichier1") fichier ruby :
malheureusement, avec un gros fichier "à supprimer", cela semble dégrader la complexité en O (N ^ 2) (mon hypothèse est que l'expression régulière a beaucoup de travail à faire), mais peut encore être utile à quelqu'un là-bas (si vous veulent plus que la suppression des lignes complètes). Cela pourrait être plus rapide dans certains cas.
Une autre option si vous optez pour la vitesse consiste à utiliser le même mécanisme de vérification du hachage, mais à "analyser" soigneusement la ligne pour les chaînes qui pourraient correspondre, puis à les comparer avec votre hachage.
En rubis, cela pourrait ressembler à ceci:
Voir aussi la réponse de Scott, similaire aux réponses awk proposées ici, et évite la complexité O (N ^ 2) (ouf).
la source