Ich möchte alle leeren Strings aus einer Liste von Strings in Python entfernen.
Meine Idee sieht so aus:
while '' in str_list:
str_list.remove('')
Gibt es einen pythonischeren Weg, um dies zu tun?
Ich möchte alle leeren Strings aus einer Liste von Strings in Python entfernen.
Meine Idee sieht so aus:
while '' in str_list:
str_list.remove('')
Gibt es einen pythonischeren Weg, um dies zu tun?
Ich würde filter
verwenden:
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)
In Python 3 gibt filter
einen Iterator zurück, daher sollte er in einem Aufruf von list()
eingehüllt werden
str_list = list(filter(None, str_list))
Vielleicht, aber timeit zeigt den Unterschied, und die Verwendung von None ist leserlicher und klarer - meiner Meinung nach! Oder ich würde sagen, die Verwendung von filter(None, l1) wird auf eine pythonische Weise aussehen.
Wenn Sie so auf Leistung gedrängt sind, ist itertools
's ifilter
sogar schneller—>>> 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
.
@BeauMartínez die Zeit für itertools.ifilter
ist nicht vollständig genau, da der Generator noch nicht ausgewertet wurde. Es sollte mit list()
umschlossen werden. filter(bool) -> 1.367577075958252, ifilter(bool) -> 0.032318115234375, list(ifilter(bool)) -> 1.8174781799316406
Die Verwendung eines Listen-Verständnisses ist der Pythonischste Weg:
>>> strings = ["first", "", "second"]
>>> [x for x in strings if x]
['first', 'second']
Wenn die Liste direkt geändert werden muss, weil es andere Referenzen gibt, die die aktualisierten Daten sehen müssen, dann verwenden Sie eine Slice-Zuweisung:
strings[:] = [x for x in strings if x]
Ich mag diese Lösung, weil sie leicht anpassbar ist. Wenn ich nicht nur leere Zeichenfolgen, sondern auch Zeichenfolgen entfernen müsste, die nur Leerzeichen sind, zum Beispiel: [x für x in Zeichenfolgen, wenn x.strip()]
.
[x für x in strings if x] Das funktioniert gut, aber können Sie bitte erklären, wie diese Schleife funktioniert??
@AmarKumar In Python wird ein leerer String in einem booleschen Kontext wie in if x
zu false ausgewertet. Die Klammern, die for
-Schleife und die if
-Klausel kombinieren, um "eine Liste zu generieren, die aus x
für jedes Element in strings
besteht, wenn x
tatsächlich etwas enthält." @Ib33x Absolut fantastische Arbeit. Diese Antwort ist sicherlich die Pythonischste.
>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(None, lstr)
['hello', ' ', 'world', ' ']
Vergleiche Zeit
>>> 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
Beachten Sie, dass filter(None, lstr)
keine leeren Zeichenfolgen mit einem Leerzeichen ' '
entfernt, es entfernt nur ''
, während ' '.join(lstr).split()
beide entfernt.
Um filter()
mit Leerzeichenzeichenfolgen entfernt zu verwenden, dauert es viel länger:
>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
18.101892948150635
Es wird nicht funktionieren, wenn Sie Leerzeichen innerhalb des Strings eines Wortes haben. zum Beispiel: ['hello world', ' ', 'hello', ' '] . >> ['helloworld', ' ', 'hello', ' '] haben Sie eine andere Lösung, um Leerzeichen innerhalb eines Elements in der Liste zu behalten, aber andere zu entfernen?
Beachten Sie, dass filter(None, lstr)
keine leeren Zeichenfolgen mit einem Leerzeichen ' '
entfernt Das liegt daran, dass es sich nicht um eine leere Zeichenfolge handelt.
D. h. alle Leerzeichen bleiben erhalten:
slist = list(filter(None, slist))
PROs:
slist = ' '.join(slist).split()
PROs:
slist = list(filter(str.strip, slist))
PROs:
## Testdaten erstellen
#
import random, string
nwords = 10000
maxlen = 30
null_ratio = 0.1
rnd = random.Random(0) # deterministische Ergebnisse
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)
]
## Testfunktionen
#
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): # verschwendet Speicher
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): # Wörter ohne(!) Leerzeichen
return ' '.join(slist).split()
## Benchmarks
#
%timeit nostrip_filter(words)
142 µs ± 16.8 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 10000 Schleifen je Durchlauf)
%timeit nostrip_comprehension(words)
263 µs ± 19.1 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 1000 Schleifen je Durchlauf)
%timeit strip_filter(words)
653 µs ± 37.5 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 1000 Schleifen je Durchlauf)
%timeit strip_filter_map(words)
642 µs ± 36 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 1000 Schleifen je Durchlauf)
%timeit strip_filter_comprehension(words)
693 µs ± 42.2 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 1000 Schleifen je Durchlauf)
%timeit strip_filter_generator(words)
750 µs ± 28.6 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 1000 Schleifen je Durchlauf)
%timeit strip_join_split(words)
796 µs ± 103 µs pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, 1000 Schleifen je Durchlauf)
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
50 Stimmen
@Ivo, keiner dieser Aussagen ist wahr. Sie sollten niemals eine Liste ändern, über die Sie iterieren, indem Sie
for x in list
verwenden. Wenn Sie einewhile-Schleife
verwenden, ist es in Ordnung. Die demonstrierte Schleife entfernt leere Zeichenfolgen, bis keine leeren Zeichenfolgen mehr vorhanden sind, und stoppt dann. Ich hatte mir tatsächlich nicht einmal die Frage angesehen (nur den Titel), aber ich habe mit genau derselben Schleife als Möglichkeit geantwortet! Wenn Sie keine Verständniskomprehensionen oder Filter verwenden möchten, um Speicherplatz zu sparen, ist dies eine sehr pythonische Lösung.4 Stimmen
Noch ein sehr gültiger Punkt, die Liste, über die Sie iterieren, niemals zu ändern :)
1 Stimmen
@EduardLuca, wenn der Zweck des Iterierens über eine Liste darin besteht, sie zu ändern, dann ist das genau das Gegenteil von dem, was du tun solltest. Du musst nur darauf achten, dass du dabei kein unerwartetes Verhalten verursachst.
1 Stimmen
@EduardLuca, @JFA : Der Punkt ist, dass er nicht über eine Liste iteriert. Er würde es tun, wenn er etwas in der Form
for var in list:
geschrieben hätte, aber hier hat erwhile const in list:
geschrieben. Das iteriert über nichts. Es wiederholt nur den gleichen Code, bis eine Bedingung falsch ist.1 Stimmen
Sie können einen Filter verwenden, um die leeren Zeichenfolgen zu entfernen. Der Code sollte so aussehen...
data = list(filter(None, str_list))