Seite 1 von 2

remove_all für Liste

Verfasst: Montag 14. Juni 2010, 19:20
von Barcellona
Hallo,


mal eine Frage, wie kann ich aus einer Liste/Hash alle Einträge löschen für ein gesuchtes Wort und
nicht nur den ersten Treffer?

Mit

Code: Alles auswählen

testarray.remove('test') # löscht den ersten Treffer aus der Liste
lösche ich das erste 'test', das sich im testarray befindet.

Wenn der Array aber 5x das Wort 'test' beinhaltet, wie kann ich dann direkt alle 5 Treffer auf einmal löschen?

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 19:33
von HerrHagen
Entweder löschst sie nacheinander:

Code: Alles auswählen

>>> x = [1,2,3,1,2,1,2,4,3,2,1]
>>> val = 1
>>> while True:
...     try:
...         x.remove(val)
...     except ValueError:
...         break
>>> x
0: [2, 3, 2, 2, 4, 3, 2]
oder du erstellt eine neue Liste:

Code: Alles auswählen

>>> x = [1,2,3,1,2,1,2,4,3,2,1]
>>> filter(lambda v:v!=1, x)
2: [2, 3, 2, 2, 4, 3, 2]
>>> [v for v in x if v!=1]
3: [2, 3, 2, 2, 4, 3, 2]

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 19:37
von Hyperion
Spontan fiel mir das ein:

Code: Alles auswählen

In [8]: from itertools import repeat

In [10]: map(l.remove, repeat("test", l.count("test")))
Out[10]: [None, None]

In [11]: l
Out[11]: ['foo', 'bar']

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 20:00
von Barcellona
Danke schön für die Antworten!

Es sollte mal sowas wie eine remove_all() Funktion für Listen in Python implementiert werden...

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 20:04
von derdon
HerrHagen: also ich bevorzuge ja die funktionale Variante 8)

Code: Alles auswählen

>>> from operator import ne
>>> from functools import partial
>>> x = [1,2,3,1,2,1,2,4,3,2,1]
>>> filter(partial(ne, 1), x)
[2, 3, 2, 2, 4, 3, 2]

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 20:06
von EyDu
Ich will auch noch eine Runde:

Code: Alles auswählen

reduce(lambda x, y: x+[y] if y!=1 else x, [1,2,3,6,4,8,9,2,5,1,6,3], [])
Oder gar so:

Code: Alles auswählen

reduce(lambda ys, x: (ys, ys[x!=1].append(x))[0], [1,2,3,6,4,8,9,2,5,1,6,3], ([], []))[1]

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 20:53
von BlackJack
So viele Lösungen und nur zwei die was taugen. Das wären die, bei denen eine neue Liste mit `filter()` erstellt wird. Die anderen gehen die Liste mehrmals durch, oder haben sogar quadratische Laufzeit.

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 21:06
von problembär

Code: Alles auswählen

while 'test' in testarray:
    testarray.remove('test')
In Python ist meine Priorität in der Regel nicht Geschwindigkeit, sondern Verständlichkeit.

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 22:06
von derdon
problembär: Von der Lesbarkeit her ist deine Lösung wirklich die beste!

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 22:13
von Defnull
Ich hätte da noch die Schul-Informatik-Unterricht-Lösung:

Code: Alles auswählen

MeineListe = list(['dies','ist','ein','test','test','test'])
try:
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
    MeineListe.remove('test')
except:
    print 'Fertig!!1'

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 22:15
von pillmuncher
Statt prozedural zu denken "wie kann ich alle ... löschen", lieber deklarativ: "dieselbe Liste, aber ohne alle ...":

Code: Alles auswählen

>>> data = ['foo', 'test', 'bar', 'test', 'zig', 'test', 'zag', 'test']
>>> print data
['foo', 'test', 'bar', 'test', 'zig', 'test', 'zag', 'test']
>>>
>>> data[:] = [each for each in data if each != 'test']
>>> print data
['foo', 'bar', 'zig', 'zag']
@problembär: das ist IMO maximal verständlich und zudem GWDW*.

Gruß,
Mick.

[*]Gschwind wia da Wind.

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 22:23
von ms4py
pillmuncher hat geschrieben:Statt prozedural zu denken "wie kann ich alle ... löschen", lieber deklarativ: "dieselbe Liste, aber ohne alle ..."
Da warst du wohl schneller, wäre auch meine Idee gewesen. :wink:
Das ist ganz klar die beste und verständlichste Lösung!

Re: remove_all für Liste

Verfasst: Montag 14. Juni 2010, 23:58
von snafu
Defnull hat geschrieben:Ich hätte da noch die Schul-Informatik-Unterricht-Lösung:
Ich find die super. :)

Re: remove_all für Liste

Verfasst: Dienstag 15. Juni 2010, 06:07
von numerix
ms4py hat geschrieben:
pillmuncher hat geschrieben:Statt prozedural zu denken "wie kann ich alle ... löschen", lieber deklarativ: "dieselbe Liste, aber ohne alle ..."
Da warst du wohl schneller, wäre auch meine Idee gewesen. :wink:
Das ist ganz klar die beste und verständlichste Lösung!
Diese Variante hatte HerrHagen doch schon gezeigt.

Re: remove_all für Liste

Verfasst: Dienstag 15. Juni 2010, 09:10
von Hyperion
problembär hat geschrieben:

Code: Alles auswählen

while 'test' in testarray:
    testarray.remove('test')
In Python ist meine Priorität in der Regel nicht Geschwindigkeit, sondern Verständlichkeit.
Hm... der Test im Schleifenkopf ist aber teuer. HerrHagen hatte das mit der Exception imho schöner gelöst. Am lesbarsten (und auch am schnellsten) ist wirklich die Lösung mit filter bzw. der äquivalenten List comprehension.

Re: remove_all für Liste

Verfasst: Dienstag 15. Juni 2010, 09:38
von snafu
Ich finde die LC wesentlich lesbarer als die Variante mit `filter()`.

Hier mal ein bißchen erweitert:

Code: Alles auswählen

In [1]: def remove_all(iterable, deletion):
   ...:     it = type(iterable)
   ...:     return it(elem for elem in iterable if elem != deletion)
   ...: 

In [2]: remove_all((3,2,4,6,4,3,2,5,3,2,1), 3)
Out[2]: (2, 4, 6, 4, 2, 5, 2, 1)

Re: remove_all für Liste

Verfasst: Dienstag 15. Juni 2010, 10:32
von lunar
@snafu: Durch die Typmagie funktioniert die Funktion faktisch nur mit Listen und Tupeln, nicht aber mit beliebigen Iteratoren. Der Name "iterable" verspricht daher mehr, als die Funktion halten kann. Wenn Du ein "iterable" akzeptierst, dann gibt auch wieder ein "iterable" zurück. Dann kann man immer noch einen anderen Konstruktor aufrufen, wenn man das möchte ... allerdings bleibt von der Funktion dann eigentlich nicht mehr genug übrig, um sie noch als Funktion zu implementieren.

Re: remove_all für Liste

Verfasst: Dienstag 15. Juni 2010, 21:51
von snafu
In welchem konkreten Fall sollte sich die Funktion denn deiner Meinung nach nicht so verhalten, wie man es bei einem `iterable`-Argument erwartet?

Re: remove_all für Liste

Verfasst: Dienstag 15. Juni 2010, 22:21
von BlackJack
@snafu: Es geht darum, dass es sich nicht nur wie ein "iterable" verhalten muss. Ein "iterable" wäre zum Beispiel ein Generatorausdruck. Damit kommt die Funktion aber nicht klar. Deshalb ist der Name sehr irreführend.

Re: remove_all für Liste

Verfasst: Mittwoch 16. Juni 2010, 07:45
von snafu
Okay, ich hätte die Funktion wirklich mit verschiedenen anderen Typen testen sollen. Da hab ich gestern offenbar gepennt.