Je veux supprimer toutes les chaînes vides d'une liste de chaînes en python.
Mon idée ressemble à ceci:
while '' in str_list:
str_list.remove('')
Y a-t-il plus moyen de faire cela en Pythonic?
Je voudrais utiliser filter
:
str_list = filter(None, str_list) # fastest
str_list = filter(bool, str_list) # fastest
str_list = filter(len, str_list) # a bit slower
str_list = filter(lambda item: item, str_list) # slower than list comprehension
Python 3 retourne un itérateur de filter
, il devrait donc être encapsulé dans un appel à list()
str_list = list(filter(None, str_list)) # fastest
( etc. )
Tests:
>>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000)
2.4797441959381104
>>> timeit('filter(bool, str_list)', 'str_list=["a"]*1000', number=100000)
2.4788150787353516
>>> timeit('filter(len, str_list)', 'str_list=["a"]*1000', number=100000)
5.2126238346099854
>>> timeit('[x for x in str_list if x]', 'str_list=["a"]*1000', number=100000)
13.354584932327271
>>> timeit('filter(lambda item: item, str_list)', 'str_list=["a"]*1000', number=100000)
17.427681922912598
strings = ["first", "", "second"]
[x for x in strings if x]
Sortie: ['first', 'second']
Edit: raccourci comme suggéré
le filtre a réellement une option spéciale pour ceci:
filter(None, sequence)
Il filtrera tous les éléments évalués à False. Pas besoin d'utiliser un appelable réel ici comme bool, len et ainsi de suite.
C'est aussi rapide que la carte (bool, ...)
>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(None, lstr)
['hello', ' ', 'world', ' ']
Comparer le temps
>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
4.226747989654541
>>> timeit('filter(None, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.0278358459472656
Notez que filter(None, lstr)
ne supprime pas les chaînes vides avec un espace ' '
, il élimine uniquement ''
tandis que ' '.join(lstr).split()
supprime les deux.
Pour utiliser filter()
sans les chaînes d'espaces, cela prend beaucoup plus de temps:
>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
18.101892948150635
Réponse de @ Ib33X est génial. Si vous voulez supprimer toutes les chaînes vides, après dépouillé. vous devez aussi utiliser la méthode strip. Sinon, la chaîne vide sera également renvoyée si elle contient des espaces. 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 à cela sera ["first", "second"]
.
Si vous voulez utiliser la méthode filter
à la place, vous pouvez faire commelist(filter(lambda item: item.strip(), strings))
. C'est donner le même résultat.
Au lieu de if x, je voudrais utiliser 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 est l'un d'entre eux, 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"]
En fonction de la taille de votre liste, il peut s'avérer plus efficace d'utiliser list.remove () plutôt que de créer une nouvelle liste:
l = ["1", "", "3", ""]
while True:
try:
l.remove("")
except ValueError:
break
Cela présente l’avantage de ne pas créer de nouvelle liste, mais l’inconvénient de devoir chercher chaque fois depuis le début, bien que, contrairement à while '' in l
tel que proposé ci-dessus, cela ne nécessite une recherche qu'une fois par occurrence de ''
( il existe certainement un moyen de garder le meilleur des deux méthodes, mais c'est plus compliqué).
Utilisez 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; de plus, lambda
est 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 items
for 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 le fait dans un temps décent.
Gardez à l'esprit que si vous souhaitez conserver les espaces blancs dans une chaîne, vous pouvez les supprimer par inadvertance en utilisant certaines approches. Si vous avez cette liste
['bonjour le monde', '', '', 'bonjour'] ce que vous voulez peut-être ['bonjour le monde', 'bonjour']
commencez par couper la liste pour convertir tout type d’espace 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]
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 la chaîne, vous pouvez utiliser filter(str.strip, lstr)
.
>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(str.strip, lstr)
['hello', 'world']
Comparer le temps sur mon pc
>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.356455087661743
>>> timeit('filter(str.strip, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
5.276503801345825
La solution la plus rapide pour supprimer ''
et les chaînes vides avec un espace ' '
reste ' '.join(lstr).split()
.
Comme indiqué dans un commentaire, la situation est différente si vos chaînes contiennent des espaces.
>>> lstr = ['hello', '', ' ', 'world', ' ', 'see you']
>>> lstr
['hello', '', ' ', 'world', ' ', 'see you']
>>> ' '.join(lstr).split()
['hello', 'world', 'see', 'you']
>>> filter(str.strip, lstr)
['hello', 'world', 'see you']
Vous pouvez voir que filter(str.strip, lstr)
préserve les chaînes avec des espaces, mais ' '.join(lstr).split()
divise cette chaîne.
Pour éliminer les vides après le décapage:
slist = map(lambda s: s and s.strip(), slist)
slist = filter(None, slist)
Quelques PROs:
rapidement, de manière sélective, en utilisant des éléments intégrés et compréhensifs.
def f1(slist):
slist = [s and s.strip() for s in slist]
return list(filter(None, slist))
def f2(slist):
slist = [s and s.strip() for s in slist]
return [s for s in slist if s]
def f3(slist):
slist = map(lambda s: s and s.strip(), slist)
return list(filter(None, slist))
def f4(slist):
slist = map(lambda s: s and s.strip(), slist)
return [s for s in slist if s]
%timeit f1(words)
10000 loops, best of 3: 106 µs per loop
%timeit f2(words)
10000 loops, best of 3: 126 µs per loop
%timeit f3(words)
10000 loops, best of 3: 165 µs per loop
%timeit f4(words)
10000 loops, best of 3: 169 µs per loop