web-dev-qa-db-fra.com

Supprimer des chaînes vides d'une liste de chaînes

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?

600
zerodx

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
1009
livibetter

Comprend la liste

strings = ["first", "", "second"]
[x for x in strings if x]

Sortie: ['first', 'second']

Edit: raccourci comme suggéré

201
Ib33X

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, ...)

62
Ivo van der Wijk
>>> 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
21
Aziz Alto

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 comme
list(filter(lambda item: item.strip(), strings)). C'est donner le même résultat.

12
ssi-anik

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"]
11
thiruvenkadam

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é).

8
Andrew Jaffe

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.

7
Aamir Mushtaq

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]
6
Reihan_amn

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.

5
Paolo Melchiorre

Pour éliminer les vides après le décapage:

slist = map(lambda s: s and s.strip(), slist)
slist = filter(None, slist)

Quelques PROs:

  • paresseux, basé sur des générateurs, pour économiser de la mémoire;
  • compréhensibilité décente du code;
  • 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
    
0
ankostis