Verwijder lege strings uit een lijst met strings

Ik wil alle lege strings verwijderen uit een lijst met strings in python.

Mijn idee ziet er als volgt uit:

while '' in str_list:
    str_list.remove('')

Is er een meer pythonische manier om dit te doen?


Antwoord 1, autoriteit 100%

Ik zou filtergebruiken:

str_list = filter(None, str_list)
str_list = filter(bool, str_list)
str_list = filter(len, str_list)
str_list = filter(lambda item: item, str_list)

Python 3 retourneert een iterator van filter, dus moet worden ingepakt in een aanroep naar list()

str_list = list(filter(None, str_list))

Antwoord 2, autoriteit 24%

Het gebruik van een lijstbegripis de meest Pythonische manier:

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

Als de lijst ter plekke moet worden aangepast, omdat er andere referenties zijn die de bijgewerkte gegevens moeten zien, gebruik dan een slice-toewijzing:

strings[:] = [x for x in strings if x]

Antwoord 3, autoriteit 6%

filter heeft hier eigenlijk een speciale optie voor:

filter(None, sequence)

Het filtert alle elementen uit die als False worden geëvalueerd. Het is niet nodig om hier een echte callable te gebruiken, zoals bool, len enzovoort.

Het is even snel als map(bool, …)


Antwoord 4, autoriteit 2%

>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(None, lstr)
['hello', ' ', 'world', ' ']

Tijd vergelijken

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

Merk op dat filter(None, lstr)lege tekenreeksen met een spatie ' 'niet verwijdert, maar alleen ''weghaalt terwijl ' '.join(lstr).split()verwijdert beide.

Om filter()te gebruiken met verwijderde witruimtetekens, kost het veel meer tijd:

>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
18.101892948150635

Antwoord 5

Antwoord van @Ib33X is geweldig. Als u elke lege string wilt verwijderen, nadat deze is gestript. je moet ook de stripmethode gebruiken. Anders wordt de lege tekenreeks ook geretourneerd als deze spaties bevat. Zoals, ” ” is ook geldig voor dat antwoord. Dus, kan worden bereikt door.

strings = ["first", "", "second ", " "]
[x.strip() for x in strings if x.strip()]

Het antwoord hiervoor is ["first", "second"].

Als u in plaats daarvan de filter-methode wilt gebruiken, kunt u het volgende doen:

list(filter(lambda item: item.strip(), strings)). Dit geeft hetzelfde resultaat.


Antwoord 6

In plaats van if x, zou ik if X != ” gebruiken om alleen lege strings te elimineren. Zoals dit:

str_list = [x for x in str_list if x != '']

Hierdoor blijft het gegevenstype Geen in uw lijst behouden. Als uw lijst gehele getallen bevat en 0 is er een van, dan blijft deze ook behouden.

Bijvoorbeeld

str_list = [None, '', 0, "Hi", '', "Hello"]
[x for x in str_list if x != '']
[None, 0, "Hi", "Hello"]

Antwoord 7

Afhankelijk van de grootte van uw lijst, kan het het meest efficiënt zijn als u list.remove() gebruikt in plaats van een nieuwe lijst te maken:

l = ["1", "", "3", ""]
while True:
  try:
    l.remove("")
  except ValueError:
    break

Dit heeft het voordeel dat er geen nieuwe lijst wordt gemaakt, maar het nadeel dat je elke keer vanaf het begin moet zoeken, hoewel in tegenstelling tot het gebruik van while '' in lzoals hierboven voorgesteld, je alleen moet zoeken eenmaal per keer dat ''voorkomt (er is zeker een manier om het beste van beide methoden te behouden, maar het is ingewikkelder).


Antwoord 8

Gebruik filter:

newlist=filter(lambda x: len(x)>0, oldlist) 

De nadelen van het gebruik van een filter zoals aangegeven, is dat het langzamer is dan alternatieven; ook is lambdameestal duur.

Of je kunt kiezen voor de eenvoudigste en meest iteratieve van allemaal:

# 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

dit is de meest intuïtieve van de methoden en doet het binnen een redelijke tijd.


Antwoord 9

Zoals gemeld door Aziz Altofilter(None, lstr)verwijdert geen lege tekenreeksen met een spatie ' 'maar als je zeker weet dat lstr alleen string bevat, kun je filter(str.strip, lstr)

gebruiken

>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(str.strip, lstr)
['hello', 'world']

Tijd vergelijken op mijn 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

De snelste oplossing om ''en lege strings met een spatie ' 'te verwijderen blijft ' '.join(lstr).split().

Zoals gemeld in een opmerking is de situatie anders als je strings spaties bevatten.

>>> 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']

Je kunt zien dat filter(str.strip, lstr)strings met spaties behoudt, maar ' '.join(lstr).split()zal dit splitsen snaren.


Antwoord 10

Houd er rekening mee dat als je de witruimtes binnen een tekenreekswilt houden, je ze met bepaalde benaderingen onbedoeld kunt verwijderen.
Als je deze lijst hebt

[‘hallo wereld’, ‘ ‘, ”, ‘hallo’]
wat je misschien wilt [‘hallo wereld’,’hallo’]

Snijd eerst de lijst bij om elk type witruimte om te zetten in een lege tekenreeks:

space_to_empty = [x.strip() for x in _text_list]

verwijder vervolgens de lege string uit de lijst met hen

space_clean_list = [x for x in space_to_empty if x]

Antwoord 11

Stel de beste antwoorden samen:

1. Elimineer leeggoed ZONDER strippen:

Dat wil zeggen, tekenreeksen voor alle spaties blijven behouden:

slist = list(filter(None, slist))

PRO’s:

  • eenvoudigste;
  • snelste (zie benchmarks hieronder).

2. Om leeggoed na het strippen te elimineren …

2.a … wanneer strings GEEN spaties tussen woorden bevatten:

slist = ' '.join(slist).split()

PRO’s:

  • kleine code
  • snel
    (MAAR niet de snelste met grote datasets vanwege geheugen, in tegenstelling tot wat @paolo-melchiorre resultaten)

2.b … wanneer strings spaties tussen woorden bevatten?

slist = list(filter(str.strip, slist))

PRO’s:

  • snelste;
  • begrijpelijkheid van de code.

Benchmarks op een machine uit 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 memory
    return 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(!) spaces
    return ' '.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)

Antwoord 12

overeenkomen met een reguliere expressie en een filter

lstr = ['hello', '', ' ', 'world', ' ']
r=re.compile('^[A-Za-z0-9]+')
results=list(filter(r.match,lstr))
print(results)

Antwoord 13

Gebruik voor een lijst met een combinatie van spaties en lege waarden eenvoudig lijstbegrip –

>>> s = ['I', 'am', 'a', '', 'great', ' ', '', '  ', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', '', 'a', '', 'joke', '', ' ', '', '?', '', '', '', '?']

Je ziet dus dat deze lijst een combinatie heeft van spaties en null-elementen. Het fragment gebruiken –

>>> d = [x for x in s if x.strip()]
>>> d
>>> d = ['I', 'am', 'a', 'great', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', 'a', 'joke', '?', '?']

Other episodes