listen replace

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.
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

Hallo da,

habt ihr eigene Listen definiert oder benutzt ihr Prozeduren, um Elemente in Listen zu ersetzten?
So sieht derzeit eine Funktion aus, die ich benutze um eine neue Kopie mit allen Ersetzungen zurückzugeben, aber glücklich bin ich damit nicht..

Code: Alles auswählen

def replace(a, b, liste):
    copy = list(liste)
    for e in copy:
        if e == a: copy[copy.index(e)] = b
    return copy
praktischer wäre eine Methode replace. Andererseits möchte ich eine eigene Klasse my_list wenn möglich umgehen. Gibts da einen Zwischenweg?

grüße,
4bit-
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Besser mit ``deepcopy`` kopieren.
Ich wuerde einen Test vorschieben, ob ``a`` ueberhaupt in der Liste ist und dann mit ``index`` ``a`` suchen.

Ungetestet:

Code: Alles auswählen

def replace(old, new, list_):
    list_ = copy.deepcopy(list_)
	if old in list_:
		position = 0
		try:
			while position <= len(list_):
				index = list_.index(old, position)
				list_[index] = new
				position = index
		except ValueError:
			return list_
	else:
		return list_
Der ``position`` Kram muss leider sein, um auch wirklich alle Treffer zu finden.
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

ok, läuft.
Ohne größere Verwirrung Stiften zu wollen: Hab die Funktion jetzt doch als Prozedur geschrieben:

Code: Alles auswählen

def replace(a, b, liste):
    for e in liste:
        if e == a: liste[liste.index(e)] = b
und die if-Abfrage weg gelassen, weil der "for e in liste" Loop nicht Rechenaufwendig ist (eine if-Abfrage für jedes Element. Eine "a in liste"-Abfrage dauert wahrscheinlich auch eine if-Abfrage "für jedes Element in Liste" lange, also etwas gleich lang).

Wenn ich aber iteriere und replace auf die...
man, jetzt funktioniert das doch. Also danke. Meine Fragen haben sich gerade von selbst beantwortet.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Code: Alles auswählen

def replace(lst, a, b):
    return [b if e == a else e for e in lst]
Stefan
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Da kann man doch noch wertvollen Festplattenspeicher sparen! ^^

Code: Alles auswählen

def replace(lst, a, b):
    return [(e,b)[e == a] for e in lst]
@4bit und cofi: Ihr steht nicht so auf "enumerate", oder?
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

EyDu hat geschrieben:@4bit und cofi: Ihr steht nicht so auf "enumerate", oder?
Naja da ich nicht ueber die Liste iteriere, braeuchte ich eine extra Liste. Die Index Zeilen sind zwar unschoen, aber ich will mir gar nich die ``enumerate``-Version vorstellen.

@4bit: Stimmt, Membership-Testing hat in Listen lineare Laufzeit. Evtl ist der Test auf ein Set trotzdem schneller als der naive Ansatz (kommt natuerlich auf die Daten an), gilt auch fuer die LC Versionen.

Uebrigens kannst du das auch den Listen anhaengen:

Code: Alles auswählen

def replace(self, old, new):
	if old in set(self):
		return [new if e == old else e for e in self]
	else:
		return self

list.replace = replace
Empfohlen hab ich das aber nicht :twisted:
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

@cofi: Danke. Gut zu wissen, falls ich doch noch nachträglich eingreifen möchte.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

cofie hat geschrieben:Die Index Zeilen sind zwar unschoen, aber ich will mir gar nich die ``enumerate``-Version vorstellen.
Schwer vorstellbar? Übersehe ich irgendwelche wichtigen Features?

Code: Alles auswählen

def replace(sequence, old, new):
    for index, element in enumerate(sequence):
        if element == old:
	    sequence[index] = new
    return sequence
Ich habe die Laufzeit nicht getestet, aber asymptotisch ist ein vorheriger Test auf Enthaltensein unnötig.
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

EyDu hat geschrieben:Übersehe ich irgendwelche wichtigen Features?
Naja, wie gesagt: Ich iteriere nicht ueber die Liste.
Aber ich merke gerade, dass die Pruefung bei der while-Schleife ueberfluessig ist, da sie eh durch den ``ValueError`` beendet wird.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

cofi hat geschrieben:Naja, wie gesagt: Ich iteriere nicht ueber die Liste.
Naja, zumindest hast du es mit "list.index" sehr gut versteckt ^^
Das Leben ist wie ein Tennisball.
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

@ EyDu: enumerate kannte ich nicht, ist aber praktisch. Habe häufiger die Situation, daß ich zwei Listen habe, deren Elemente zusammengehören, wenn sie die gleichen Indizies haben. Sowas:

Code: Alles auswählen

menge = [1,2,3,4]
zeichen = ["+", "-", "+", "+"]
for ding in menge
    if zeichen[menge.index(ding)] == "-": print "oh no!"
Das geht mit enumerate übersichtlicher:

Code: Alles auswählen

for i, ding in enumerate(menge):
    if zeichen[i] == "-": print "huch!"
was bei den Beispielen nicht so gut rüber kommt ist, daß von Anfang an über den Index gehen (mit "range(len(menge))") manchmal nicht so übersichtlich ist. Zum Beispiel wenn "menge" aus komplizierteren Dingen besteht als Integers, die man selbst wieder per index auswählt.

In jedem Fall ist enumerate praktisch, weil sozusagen die Iteration über den Index sowie die Index-freie Iteration über die Elemente gleichzeitig zur Verfügung stehen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@4bit: Wobei Deine beiden Beispiele hier sich viel einfache lösen ließen, da Du menge und zeichen quasi nicht miteinander verknüpfst:

Code: Alles auswählen

for token in zeichen:
    if zeichen == "-":
        print "Huch"
Will man die beiden Mengen verknüpfen würde ich das ggf. auch mit zip lösen:

Code: Alles auswählen

menge = [1,2,3,4]
zeichen = ["+", "-", "+", "+"]
for element, token in zip(menge, zeichen):
    if element == "-":
        print element, token
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

@Hyperion: aha. Also "zip" und "enumerate" machen in diesem Fall für den Programmierer keinen Unterschied. "zip" ist wohl etwas allgemeiner als "enumerate".
man könnte meinen, daß

Code: Alles auswählen

enumerate(liste) == zip(range(len(liste)), liste)
gilt. (Aber das eine gibt eine Liste zurück und enumerate ein "enumerate-Objekt").
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

4bit hat geschrieben:@Hyperion: aha. Also "zip" und "enumerate" machen in diesem Fall für den Programmierer keinen Unterschied. "zip" ist wohl etwas allgemeiner als "enumerate".
Hm... naja, zip und enumerate sind zwei vollkommen verschiedene Sachen. Enumerate erzeugt zu einer Liste einen Index und zip vereinigt einfach die Elemente aus zwei Listen zu Paaren. Da Deine eine Liste im Beispiel nur aus aufsteigenden Zahlen besteht, sieht das Ergebnis natürlich ähnlich aus.
BlackJack

@4bit: ``enumerate(liste)`` entspricht eher ``izip(count(), liste)`` mit `izip()` und `count()` aus dem `itertools`-Modul.

Ich habe so ein bisschen das Gefühl, dass Du Python nicht "richtig" verwendest, denn ich hatte soweit ich mich erinnere noch nie Verwendung für so eine `replace()`-Prozedur, ich schreibe da lieber Funktionen, noch verschiedene Listen wo die Elemente eigentlich zusammen gehören.
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Es gibt auch die Möglichkeit das ganze mit der replace-Methode für strings zu lösen.

Hier ist mein Ansatz:

Code: Alles auswählen

>>> def replace(liste, old, new):
	return (str(liste).replace(str(old), str(new))).split('[')[1].split(']')[0].split(', ')

>>> replace(range(10), 4, 0)
['0', '1', '2', '3', '0', '5', '6', '7', '8', '9']
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Pascal hat geschrieben:Es gibt auch die Möglichkeit das ganze mit der replace-Methode für strings zu lösen.
Nichts fuer ungut, Dein Beispiel ist aber am Ende nicht mehr als Spielerei. Dein Code ist uneffizient und unflexibel. Wuerde niemand so machen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@Pascal: dafür müsstest du aber "funktioniert" ganz neu definieren.

Code: Alles auswählen

replace(["[", "1,2", "]", 4, 5], 4, 42)

Code: Alles auswählen

replace([{1:2, 3:4, 5:6}], 4, 42)
Das Leben ist wie ein Tennisball.
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

hendrikS hat geschrieben:
Pascal hat geschrieben:Es gibt auch die Möglichkeit das ganze mit der replace-Methode für strings zu lösen.
Nichts fuer ungut, Dein Beispiel ist aber am Ende nicht mehr als Spielerei. Dein Code ist uneffizient und unflexibel. Wuerde niemand so machen.
Ich wollt ja lediglich einen anderen Lösungsvorschlag präsentieren.
Und das es auch bei komplexeren Listen nicht ganz funktinoniert hat ja EyDu schon gezeigt ;)
BlackJack

@Pascal: Das ist vielleicht ein Vorschlag gewesen, aber keine Lösung. Wenn man eine Sprache haben möchte, bei Datenstrukturen über Zeichenketten simuliert werden, sollte man Shell- oder Tcl-Skripte schreiben, aber bitte nicht Python. :roll:
Antworten