@Ivo, aucune de ces affirmations n'est vraie. Vous ne devez jamais modifier une liste que votre itération sur l'utilisation for x in listSi vous utilisez un while loopalors c'est très bien. la boucle démontrée supprimera les chaînes vides jusqu'à ce qu'il n'y ait plus de chaînes vides, puis s'arrêtera. En fait, je n'avais même pas regardé la question (juste le titre) mais j'ai répondu avec la même boucle exacte que possible! Si vous ne voulez pas utiliser de compréhensions ou de filtres pour la mémoire, c'est une solution très pythonique.
aaronasterling
4
Encore un point très valable pour ne jamais changer la liste que vous parcourez :)
Eduard Luca
1
@EduardLuca si le but d'itérer sur une liste est de la changer, c'est le contraire de ce que vous devez faire. Vous devez juste faire attention à ne pas provoquer un comportement inattendu en le faisant.
JFA
1
@EduardLuca, @JFA: Le fait est qu'il n'itère PAS sur une liste. Il le ferait s'il avait écrit quelque chose sous la forme for var in list:, mais ici, il a écrit while const in list:. qui n’itère pas sur quoi que ce soit. c'est simplement répéter le même code jusqu'à ce qu'une condition soit fausse.
Si vous êtes que pressé pour la performance, itertooll »ifilter est même faster- >>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000)2.3468542098999023; >>> timeit('itertools.ifilter(None, str_list)', 'str_list=["a"]*1000', number=100000)0.04442191123962402.
Humphrey Bogart
4
@cpburnz Très vrai. Cependant, les ifilterrésultats sont évalués paresseusement, pas d'un seul coup - je dirais que pour la plupart des cas, ifilterc'est mieux. Il filterest intéressant de noter que l'utilisation est toujours plus rapide que d'envelopper un ifilterdans un list.
Humphrey Bogart le
3
Si vous effectuez cette opération sur une liste de nombres, notez que les zéros seront également supprimés (remarque: je n'ai utilisé que les 3 premières méthodes), vous aurez donc besoin d'une autre méthode.
SnoringFrog
2
Cela se concentre uniquement sur la vitesse, pas sur le caractère pythonique de la solution (la question qui a été posée). Les compréhensions de liste sont la solution pythonique, et le filtre ne doit être utilisé que si le profilage a prouvé que listcomp est un goulot d'étranglement.
Tritium21
3
@ whoever-mentions-about-or-imply-Python-3, veuillez simplement modifier et mettre à jour la réponse. Nous ne discutions que pour Python 2 lorsque cette question a été posée, même Python 3 est sorti presque 2 ans. Mais mettez à jour les résultats Python 2 et 3.
J'aime cette solution car elle est facilement adaptable. Si je devais retirer non seulement des chaînes vides , mais les chaînes qui sont juste des espaces, par exemple: [x for x in strings if x.strip()].
Bond
67
le filtre a en fait une option spéciale pour cela:
filter(None, sequence)
Il filtrera tous les éléments évalués comme faux. Pas besoin d'utiliser un véritable appelable ici comme bool, len et ainsi de suite.
C'est un idiome python, en fait. C'est aussi la seule fois où j'utilise encore filter (), les compréhensions de liste ont pris le dessus partout ailleurs.
Notez que filter(None, lstr)cela ne supprime pas les chaînes vides avec un espace ' ', il ne taille ''que pendant qu'il ' '.join(lstr).split()supprime les deux.
Pour utiliser filter()avec les chaînes d'espaces supprimées, cela prend beaucoup plus de temps:
>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])',"lstr=['hello', '', ' ', 'world', ' ']", number=10000000)18.101892948150635
cela ne fonctionnera pas si vous avez de l'espace parmi la chaîne d'un mot. par exemple: ['Bonjour tout le monde', '', 'Bonjour', '']. >> ['helloworld', '', 'hello', ''] avez-vous une autre solution pour conserver des espaces dans un élément de la liste mais en supprimer d'autres?
Reihan_amn
Notez que filter(None, lstr)cela ne supprime pas les chaînes vides avec un espace' ' Oui, car ce n'est pas une chaîne vide.
AMC
15
La réponse de @ Ib33X est géniale. Si vous souhaitez supprimer toutes les chaînes vides, après les avoir supprimées. vous devez également utiliser la méthode des bandes. Sinon, il renverra également la chaîne vide s'il contient des espaces blancs. Par exemple, "" sera également valable pour cette réponse. Donc, peut être atteint par.
strings =["first","","second "," "][x.strip()for x in strings if x.strip()]
La réponse sera ["first", "second"].
Si vous souhaitez utiliser la filterméthode à la place, vous pouvez faire comme
list(filter(lambda item: item.strip(), strings)). Cela donne le même résultat.
Au lieu de if x, j'utiliserais if X! = '' Afin d'éliminer simplement les chaînes vides. Comme ça:
str_list =[x for x in str_list if x !='']
Cela préservera le type de données Aucun dans votre liste. De plus, si votre liste contient des entiers et que 0 en fait partie, elle sera également conservée.
Par exemple,
str_list =[None,'',0,"Hi",'',"Hello"][x for x in str_list if x !=''][None,0,"Hi","Hello"]
Si vos listes ont des types disparates (sauf Aucun), vous pouvez avoir un problème plus important.
Tritium21
Quels types? J'ai essayé avec int et d'autres types numériques, chaînes, listes, tupes, ensembles et Aucun et aucun problème là-bas. Je pourrais voir que s'il existe des types définis par l'utilisateur qui ne prennent pas en charge la méthode str, cela pourrait poser un problème. Dois-je m'inquiéter pour un autre?
thiruvenkadam
1
Si vous en avez un str_list = [None, '', 0, "Hi", '', "Hello"], c'est le signe d'une application mal conçue. Vous ne devriez pas avoir plus d'une interface (type) et Aucune dans la même liste.
Tritium21
3
Récupérer des données de db? liste d'arguments pour une fonction lors de tests automatisés?
thiruvenkadam
3
Ce sont généralement des tuples.
Tritium21
7
Selon la taille de votre liste, cela peut être plus efficace si vous utilisez list.remove () plutôt que de créer une nouvelle liste:
l =["1","","3",""]whileTrue:try:
l.remove("")exceptValueError:break
Cela a l'avantage de ne pas créer une nouvelle liste, mais l'inconvénient d'avoir à chercher à chaque fois depuis le début, bien que contrairement à l'utilisation while '' in lcomme proposé ci-dessus, cela ne nécessite une recherche qu'une fois par occurrence de ''(il existe certainement un moyen de conserver le meilleur de les deux méthodes, mais c'est plus compliqué).
Vous pouvez modifier la liste en place en faisant ary[:] = [e for e in ary if e]. Beaucoup plus propre et n'utilise pas d'exceptions pour contrôler le flux.
Krzysztof Karski
2
Eh bien, ce n'est pas vraiment "en place" - je suis presque sûr que cela crée une nouvelle liste et l'attribue simplement au nom de l'ancien.
Andrew Jaffe
Cela fonctionne très mal car la queue de données est mélangée dans la mémoire à chaque retrait. Mieux vaut supprimer tout en un coup.
wim
7
Gardez à l'esprit que si vous souhaitez conserver les espaces blancs dans une chaîne , vous pouvez les supprimer involontairement en utilisant certaines approches. Si vous avez cette liste
['bonjour le monde', '', '', 'bonjour'] ce que vous voudrez peut-être ['bonjour le monde', 'bonjour']
coupez d'abord la liste pour convertir tout type d'espace blanc en chaîne vide:
space_to_empty =[x.strip()for x in _text_list]
puis supprimez la chaîne vide de leur liste
space_clean_list =[x for x in space_to_empty if x]
si vous souhaitez conserver les espaces blancs dans une chaîne, vous pouvez les supprimer involontairement en utilisant certaines approches. Vous aimez cette approche, alors?
AMC
Merci mec, ça a fonctionné pour moi avec un petit changement. à savoirspace_clean_list = [x.strip() for x in y if x.strip()]
Muhammad Mehran Khan Attari
6
Utilisation filter:
newlist=filter(lambda x: len(x)>0, oldlist)
L'inconvénient de l'utilisation du filtre comme indiqué est qu'il est plus lent que les alternatives; aussi, lambdaest généralement coûteux.
Ou vous pouvez opter pour le plus simple et le plus itératif de tous:
# I am assuming listtext is the original list containing (possibly) empty itemsfor item in listtext:if item:
newlist.append(str(item))# You can remove str() based on the content of your original list
c'est la plus intuitive des méthodes et elle le fait en temps décent.
Bienvenue chez SO. Vous n'avez pas été ignoré. Vous n'avez pas été attaqué par un électeur abattu non anodin. Vous avez reçu des commentaires. Amplification: le premier argument proposé pour le filtre est pire que lambda x: len(x)ce qui est pire que lambda x : xla pire des 4 solutions dans la réponse sélectionnée. Un fonctionnement correct est préférable, mais pas suffisant. Passez votre curseur sur le bouton downvote: il dit "Cette réponse n'est pas utile".
John Machin
5
Comme indiqué par Aziz Altofilter(None, lstr) ne supprime pas les chaînes vides avec un espace ' 'mais si vous êtes sûr que lstr ne contient que des chaînes, vous pouvez utiliserfilter(str.strip, lstr)
Cela ne fonctionne que si vos chaînes ne contiennent pas d'espaces. Sinon, vous divisez également ces chaînes.
phillyslick
1
@BenPolinsky, comme vous l'avez signalé join, divisera les chaînes avec de l'espace, mais pas le filtre. Merci pour ton commentaire J'ai amélioré ma réponse.
Paolo Melchiorre
-1
Résumez les meilleures réponses:
1. Éliminez les vides SANS décapage:
Autrement dit, les chaînes de tous les espaces sont conservées:
slist = list(filter(None, slist))
Avantages:
le plus simple;
plus rapide (voir les repères ci-dessous).
2. Pour éliminer les vides après décapage ...
2.a ... lorsque les chaînes ne contiennent PAS d'espaces entre les mots:
slist =' '.join(slist).split()
Avantages:
petit code
rapide (MAIS pas plus rapide avec les grands ensembles de données en raison de la mémoire, contrairement aux résultats @ paolo-melchiorre)
2.b ... lorsque les chaînes contiennent des espaces entre les mots?
slist = list(filter(str.strip, slist))
Avantages:
le plus rapide;
compréhensibilité du code.
Repères sur une machine 2018:
## Build test-data#import random, string
nwords =10000
maxlen =30
null_ratio =0.1
rnd = random.Random(0)# deterministic results
words =[' '* rnd.randint(0, maxlen)if rnd.random()>(1- null_ratio)else''.join(random.choices(string.ascii_letters, k=rnd.randint(0, maxlen)))for _i in range(nwords)]## Test functions#def nostrip_filter(slist):return list(filter(None, slist))def nostrip_comprehension(slist):return[s for s in slist if s]def strip_filter(slist):return list(filter(str.strip, slist))def strip_filter_map(slist):return list(filter(None, map(str.strip, slist)))def strip_filter_comprehension(slist):# waste memoryreturn list(filter(None,[s.strip()for s in slist]))def strip_filter_generator(slist):return list(filter(None,(s.strip()for s in slist)))def strip_join_split(slist):# words without(!) spacesreturn' '.join(slist).split()## Benchmarks#%timeit nostrip_filter(words)142µs ±16.8µs per loop (mean ± std. dev. of 7 runs,10000 loops each)%timeit nostrip_comprehension(words)263µs ±19.1µs per loop (mean ± std. dev. of 7 runs,1000 loops each)%timeit strip_filter(words)653µs ±37.5µs per loop (mean ± std. dev. of 7 runs,1000 loops each)%timeit strip_filter_map(words)642µs ±36µs per loop (mean ± std. dev. of 7 runs,1000 loops each)%timeit strip_filter_comprehension(words)693µs ±42.2µs per loop (mean ± std. dev. of 7 runs,1000 loops each)%timeit strip_filter_generator(words)750µs ±28.6µs per loop (mean ± std. dev. of 7 runs,1000 loops each)%timeit strip_join_split(words)796µs ±103µs per loop (mean ± std. dev. of 7 runs,1000 loops each)
s and s.strip()peut être simplifié à juste s.strip().
AMC
s and s.strip()est nécessaire si nous voulons reproduire entièrement filter(None, words), la réponse acceptée. J'ai corrigé x2 exemples de fonctions ci-dessus et supprimé x2 mauvaises.
ankostis
-2
Pour une liste avec une combinaison d'espaces et de valeurs vides, utilisez la compréhension de liste simple -
>>> s =['I','am','a','','great',' ','',' ','person','!!','Do','you','think','its','a','','a','','joke','',' ','','?','','','','?']
Donc, vous pouvez voir, cette liste a une combinaison d'espaces et d'éléments nuls. Utilisation de l'extrait -
>>> d =[x for x in s if x.strip()]>>> d
>>> d =['I','am','a','great','person','!!','Do','you','think','its','a','a','joke','?','?']
for x in list
Si vous utilisez unwhile loop
alors c'est très bien. la boucle démontrée supprimera les chaînes vides jusqu'à ce qu'il n'y ait plus de chaînes vides, puis s'arrêtera. En fait, je n'avais même pas regardé la question (juste le titre) mais j'ai répondu avec la même boucle exacte que possible! Si vous ne voulez pas utiliser de compréhensions ou de filtres pour la mémoire, c'est une solution très pythonique.for var in list:
, mais ici, il a écritwhile const in list:
. qui n’itère pas sur quoi que ce soit. c'est simplement répéter le même code jusqu'à ce qu'une condition soit fausse.Réponses:
J'utiliserais
filter
:Python 3 renvoie un itérateur de
filter
, devrait donc être encapsulé dans un appel àlist()
la source
itertool
l »ifilter
est même faster->>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000)
2.3468542098999023
;>>> timeit('itertools.ifilter(None, str_list)', 'str_list=["a"]*1000', number=100000)
0.04442191123962402
.ifilter
résultats sont évalués paresseusement, pas d'un seul coup - je dirais que pour la plupart des cas,ifilter
c'est mieux. Ilfilter
est intéressant de noter que l'utilisation est toujours plus rapide que d'envelopper unifilter
dans unlist
.Utiliser une compréhension de liste est la manière la plus Pythonique:
Si la liste doit être modifiée sur place, car d'autres références doivent voir les données mises à jour, utilisez une affectation de tranche:
la source
[x for x in strings if x.strip()]
.le filtre a en fait une option spéciale pour cela:
Il filtrera tous les éléments évalués comme faux. Pas besoin d'utiliser un véritable appelable ici comme bool, len et ainsi de suite.
C'est aussi rapide que la carte (bool, ...)
la source
Comparez le temps
Notez que
filter(None, lstr)
cela ne supprime pas les chaînes vides avec un espace' '
, il ne taille''
que pendant qu'il' '.join(lstr).split()
supprime les deux.Pour utiliser
filter()
avec les chaînes d'espaces supprimées, cela prend beaucoup plus de temps:la source
filter(None, lstr)
cela ne supprime pas les chaînes vides avec un espace' '
Oui, car ce n'est pas une chaîne vide.La réponse de @ Ib33X est géniale. Si vous souhaitez supprimer toutes les chaînes vides, après les avoir supprimées. vous devez également utiliser la méthode des bandes. Sinon, il renverra également la chaîne vide s'il contient des espaces blancs. Par exemple, "" sera également valable pour cette réponse. Donc, peut être atteint par.
La réponse sera
["first", "second"]
.Si vous souhaitez utiliser la
filter
méthode à la place, vous pouvez faire commelist(filter(lambda item: item.strip(), strings))
. Cela donne le même résultat.la source
Au lieu de if x, j'utiliserais if X! = '' Afin d'éliminer simplement les chaînes vides. Comme ça:
Cela préservera le type de données Aucun dans votre liste. De plus, si votre liste contient des entiers et que 0 en fait partie, elle sera également conservée.
Par exemple,
la source
str_list = [None, '', 0, "Hi", '', "Hello"]
, c'est le signe d'une application mal conçue. Vous ne devriez pas avoir plus d'une interface (type) et Aucune dans la même liste.Selon la taille de votre liste, cela peut être plus efficace si vous utilisez list.remove () plutôt que de créer une nouvelle liste:
Cela a l'avantage de ne pas créer une nouvelle liste, mais l'inconvénient d'avoir à chercher à chaque fois depuis le début, bien que contrairement à l'utilisation
while '' in l
comme proposé ci-dessus, cela ne nécessite une recherche qu'une fois par occurrence de''
(il existe certainement un moyen de conserver le meilleur de les deux méthodes, mais c'est plus compliqué).la source
ary[:] = [e for e in ary if e]
. Beaucoup plus propre et n'utilise pas d'exceptions pour contrôler le flux.Gardez à l'esprit que si vous souhaitez conserver les espaces blancs dans une chaîne , vous pouvez les supprimer involontairement en utilisant certaines approches. Si vous avez cette liste
['bonjour le monde', '', '', 'bonjour'] ce que vous voudrez peut-être ['bonjour le monde', 'bonjour']
coupez d'abord la liste pour convertir tout type d'espace blanc en chaîne vide:
puis supprimez la chaîne vide de leur liste
la source
space_clean_list = [x.strip() for x in y if x.strip()]
Utilisation
filter
:L'inconvénient de l'utilisation du filtre comme indiqué est qu'il est plus lent que les alternatives; aussi,
lambda
est généralement coûteux.Ou vous pouvez opter pour le plus simple et le plus itératif de tous:
c'est la plus intuitive des méthodes et elle le fait en temps décent.
la source
lambda x: len(x)
ce qui est pire quelambda x : x
la pire des 4 solutions dans la réponse sélectionnée. Un fonctionnement correct est préférable, mais pas suffisant. Passez votre curseur sur le bouton downvote: il dit "Cette réponse n'est pas utile".Comme indiqué par Aziz Alto
filter(None, lstr)
ne supprime pas les chaînes vides avec un espace' '
mais si vous êtes sûr que lstr ne contient que des chaînes, vous pouvez utiliserfilter(str.strip, lstr)
Comparer le temps sur mon PC
La solution la plus rapide pour supprimer
''
et vider les chaînes avec un espace' '
reste' '.join(lstr).split()
.Comme indiqué dans un commentaire, la situation est différente si vos chaînes contiennent des espaces.
Vous pouvez voir que
filter(str.strip, lstr)
conserver les chaînes avec des espaces, mais' '.join(lstr).split()
diviser ces chaînes.la source
join
, divisera les chaînes avec de l'espace, mais pas le filtre. Merci pour ton commentaire J'ai amélioré ma réponse.Résumez les meilleures réponses:
1. Éliminez les vides SANS décapage:
Autrement dit, les chaînes de tous les espaces sont conservées:
Avantages:
2. Pour éliminer les vides après décapage ...
2.a ... lorsque les chaînes ne contiennent PAS d'espaces entre les mots:
Avantages:
2.b ... lorsque les chaînes contiennent des espaces entre les mots?
Avantages:
Repères sur une machine 2018:
la source
s and s.strip()
peut être simplifié à justes.strip()
.s and s.strip()
est nécessaire si nous voulons reproduire entièrementfilter(None, words)
, la réponse acceptée. J'ai corrigé x2 exemples de fonctions ci-dessus et supprimé x2 mauvaises.Pour une liste avec une combinaison d'espaces et de valeurs vides, utilisez la compréhension de liste simple -
Donc, vous pouvez voir, cette liste a une combinaison d'espaces et d'éléments nuls. Utilisation de l'extrait -
la source