Seite 1 von 1

"for l in list" mit remove...

Verfasst: Montag 7. Januar 2008, 12:40
von nonsenz
hallo,

erstmal tschuldigung wegen des komischen Titels, mir viel nichts besseres ein. Nun zu meinem Problem:
Ich suche eine elegante Lösung um aus einer Liste bestimmte elemente zu entfernen:

Code: Alles auswählen

def delCourses(self,ids):
     for c in self.courses:
         if c.id in ids:
             self.courses.remove(c)
(ids ist eine liste von zahlen)
Wenn ich das so versuche, wird immer das element nach dem entfernten übersprungen (index verschiebt sich scheinbar). Wie löse ich das am besten. Mir fallen unterschiedliche Lösungen ein (z.B. nicht zu entfernende in neue Liste übernehemen), aber keine scheint mir so richtig sauber.
Irgendjemand eine Idee?

Danke und ciao,
nons

Verfasst: Montag 7. Januar 2008, 12:45
von Zap
Am besten ist es eine neue Liste zu erstellen:

Code: Alles auswählen

def DeleteCourses(self, ids):
    self.courses = [c for c in self.courses if c.id not in ids]

Verfasst: Montag 7. Januar 2008, 12:49
von Rebecca
Erstelle eine neue Liste. In deinem Fall kanns du eine List Comprehension verwenden (ungetestet):

Code: Alles auswählen

new = [c for c in self.courses if c.id not in ids]

Verfasst: Montag 7. Januar 2008, 13:25
von nonsenz
Super, vielen Dank. Diese Schreibweise war mir unbekannt.

Verfasst: Montag 7. Januar 2008, 18:18
von sma
Du könntest auch

Code: Alles auswählen

for c in list(courses):
    if c.id in ids:
        courses.remove(c)
oder

Code: Alles auswählen

courses = filter(lambda c: c.id in ids, courses)
benutzen, wenn dir die list comprehension nicht so zusagt. Ich denke aber, diese Form ist die lesbarste.

Stefan

Verfasst: Dienstag 8. Januar 2008, 17:39
von birkenfeld
Eine for-Schleife mit remove() ist bäh, weil sie im allgemeinen quadratische Laufzeit hat.

Wenn, dann so:

Code: Alles auswählen

for i xrange(len(courses)-1, -1, -1):
    if courses[i].id in ids:
        del courses[i]
Das ist zwar nicht schön anzusehen, aber sehr effizient, da es keine weiteren Listen erzeugt und nur einmal über die Liste iteriert, also lineare Laufzeit hat.

Verfasst: Dienstag 8. Januar 2008, 19:35
von BlackJack
Ein bisschen hübscher wird es IMHO wenn man `reversed()` verwendet:

Code: Alles auswählen

for i in reversed(xrange(len(courses))):

Verfasst: Dienstag 8. Januar 2008, 22:47
von Hyperion
aber erzeugt reversed() nicht wieder ne neue Liste?

Verfasst: Dienstag 8. Januar 2008, 23:26
von BlackJack
Nein, einen Iterator. Und `xrange`-Objekte haben auch eine spezielle `__reverse__`-Methode.

Code: Alles auswählen

In [87]: reversed(xrange(10))
Out[87]: <rangeiterator object at 0x8346968>

In [88]: xrange.__reversed__?
Type:           method_descriptor
Base Class:     <type 'method_descriptor'>
String Form:    <method '__reversed__' of 'xrange' objects>
Namespace:      Python builtin
Docstring:
    Returns a reverse iterator.