"for l in list" mit remove...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
nonsenz
User
Beiträge: 14
Registriert: Montag 23. Januar 2006, 15:40

Montag 7. Januar 2008, 12:40

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
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Montag 7. Januar 2008, 12:45

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]
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Montag 7. Januar 2008, 12:49

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]
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
nonsenz
User
Beiträge: 14
Registriert: Montag 23. Januar 2006, 15:40

Montag 7. Januar 2008, 13:25

Super, vielen Dank. Diese Schreibweise war mir unbekannt.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Montag 7. Januar 2008, 18:18

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
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Dienstag 8. Januar 2008, 17:39

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
BlackJack

Dienstag 8. Januar 2008, 19:35

Ein bisschen hübscher wird es IMHO wenn man `reversed()` verwendet:

Code: Alles auswählen

for i in reversed(xrange(len(courses))):
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dienstag 8. Januar 2008, 22:47

aber erzeugt reversed() nicht wieder ne neue Liste?
BlackJack

Dienstag 8. Januar 2008, 23:26

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