Seite 1 von 1

Verschieden Optimierungsfragen

Verfasst: Freitag 23. Dezember 2011, 22:47
von Ande
Hallo zusammen,

1.
nehmen wir an:

Code: Alles auswählen

a = 'anfang'
a += machWasMitString(string1)
a += machWasMitString(string2)
etc ...
währe

Code: Alles auswählen

a = []
a.append('anfang')
a.append(machWasMitString(string1))
a.append(machWasMitString(string2))
etc ...
fertig = ''.join(a)
schneller? Oder gibts da noch ne andere herangehensweise, die besser ist?

2.

Code: Alles auswählen

slist = [some_function(elt) for elt in somelist]
s = "".join(slist)
Das funktioniert gut für eine Liste, wenn ich aber diese Funktion auf 2 verschieden Listen abwechselnd anwenden will, geht das auch so ähnlich?

Code: Alles auswählen

list1 = [...]
list2 = [...]# gleiche größe/länge wie list1
list3 = []
for n in range(len(list1)):
    list3.append(list1[n])
    list3.append(list2[n])

Re: Verschieden Optimierungsfragen

Verfasst: Freitag 23. Dezember 2011, 23:15
von BlackJack
@Ande: Zeichenketten durch wiederholtes ``+``/``+=`` zusammen zu setzen ist potentiell ineffizient(er) als es mittels `join()` zu machen. CPython versucht im ersten Fall etwas zu optimieren, aber da kann man sich ganz grundsätzlich nicht drauf verlassen.

Wenn das Beispiel tatsächlich so aussieht, wie Du es gezeigt hast, könntest Du das erste `append()` sparen und den Inhalt gleich in die Liste schreiben.

Code: Alles auswählen

a = ['anfang']
# ...
Bei Deinem zweiten (1.) Beispiel kannst Du `slist` einsparen und die „list comprehension“ durch einen Generatorausdruck ersetzen und den direkt an `join()` übergeben. Eventuell könnte auch `itertools.imap()` nützlich sein.

Code: Alles auswählen

s = ''.join(imap(some_function, some_iterable))
``for i in range(len(obj)):`` ist ein „Anti-Pattern“ in Python. Hier würde man eher `zip()` beziehungsweise `itertools.izip()` verwenden:

Code: Alles auswählen

list3 = list()
for items in izip(list1, list2):
    list3.extend(items)

Re: Verschieden Optimierungsfragen

Verfasst: Freitag 23. Dezember 2011, 23:17
von cofi
Ad 1: Hier hilft nur Profiling, Profiling und Profiling.
Allerdings sind Strings immutable, d.h. in jedem `+=` wird ein neuer String erzeugt.
Aber wenn du an der Stelle optimieren willst, bist du bei der falschen Sprache.

Ad 2: `itertools.izip`: http://docs.python.org/library/itertool ... tools.izip

Code: Alles auswählen

for t in itertools.izip(list1, list2, list3, ...):
    list0.extend(t)
Edit: Hach schon wieder zu langsam.

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 00:12
von needsch
Zum Thema String concatenation:

Code: Alles auswählen

"".join(listOfStrings)
ist die beste Variante, weil einfach und verdammt schnell. Ich verweise auf diesen String concatenation benchmark. :)

Zu deiner zweiten Frage:
Ich verstehe nicht ganz, was du meinst mit "Funktion abwechselnd auf 2 Listen anwenden". Dein Beispiel-Code hat mir leider auch nicht eingeleuchtet, weil da nichts abgewechselt wird. :?:

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 00:21
von BlackJack
@needsch: `list3` enthält hinterher abwechselnd Elemente aus `list1` und `list2`.

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 18:10
von Leonidas
BlackJack hat geschrieben:``for i in range(len(obj)):`` ist ein „Anti-Pattern“ in Python. Hier würde man eher `zip()` beziehungsweise `itertools.izip()` verwenden:

Code: Alles auswählen

list3 = list()
for items in izip(list1, list2):
    list3.extend(items)
Heh, witziger Trick um die Elemente abzuwechseln. Allerdings nicht unbedingt straightforward, und wenn man eine Funktion auf die Elemente anwenden will muss man es dann doch wieder umständlicher machen.

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 21:47
von DasIch
Ich würde die Schleife möglichst vermeiden:

Code: Alles auswählen

>>> from itertools import chain, izip
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> list(chain.from_iterable(izip(a, b)))
[1, 4, 2, 5, 3, 6]

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 23:06
von Ande
Danke schonmal für die Info.

Könnte man map auch mit einer Funktion benutzen, die mehrere Argumente hat, aber von z.B. dem zweiten Argument(eine Liste) nicht jeweils ein Element sondern die ganze Liste an die Funktion weitergegeben werden soll?

Code: Alles auswählen

def funktion( jeweilsElement, liste):
    # code mit element
    # code mit liste

list0 = [...]
list1 = [...]
test = map(funktion, list0, ?)

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 23:16
von DasIch
Da map sich ähnlich wie izip_longest verhält geht es leider nicht sonderlich elegant aber man kann folgendes machen:

Code: Alles auswählen

>>> def foo(item, items):
...     return [item] + items
... 
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> map(foo, a, [b] * len(a))
[[1, 4, 5, 6], [2, 4, 5, 6], [3, 4, 5, 6]]
Funktioniert allerdings nur einwandfrei wenn weder b noch die Elemente in b verändert werden.

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 23:39
von Ande
Hmm oke danke. Wegen dem profiling, mein programm ist ein PlugIn für eine Software, die Funktionen werden also durch die Software aufgerufen und das Script greift auch auf variablen etc aus der Software zu. Bis jetzt hab ich bei den profilern nur gesehen, dass man zb profiler.run(funktionsname) macht, könnte ich den profiler auch "nebenbei" laufen lassen, ihn also wenn der script ausgeführt wird "anschalten"?

Re: Verschieden Optimierungsfragen

Verfasst: Samstag 24. Dezember 2011, 23:40
von BlackJack
Zwei Alternativen mit `imap()` und `repeat()` aus dem `itertools`-Modul beziehungsweise mit `functools.partial()`:

Code: Alles auswählen

In [312]: list(imap(foo, a, repeat(b)))
Out[312]: [[1, 4, 5, 6], [2, 4, 5, 6], [3, 4, 5, 6]]

In [313]: map(partial(foo, items=b), a)
Out[313]: [[1, 4, 5, 6], [2, 4, 5, 6], [3, 4, 5, 6]]

Re: Verschieden Optimierungsfragen

Verfasst: Sonntag 25. Dezember 2011, 11:37
von problembär
BlackJack hat geschrieben:``for i in range(len(obj)):`` ist ein „Anti-Pattern“ in Python. Hier würde man eher `zip()` beziehungsweise `itertools.izip()` verwenden:

Code: Alles auswählen

list3 = list()
for items in izip(list1, list2):
    list3.extend(items)
... was allerdings (im Vergleich zum "Anti-Pattern") ganz schöner Krampf ist.

Re: Verschieden Optimierungsfragen

Verfasst: Sonntag 25. Dezember 2011, 11:47
von BlackJack
@problembär: Was ist daran „Krampf“? Es kommt mit weniger Quelltext aus, ist einfach und direkt, und ist allgemeiner, da es keine Sequenzen voraussetzt, sondern mit beliebigen „iterables“ funktioniert. Noch besser ist allerdings der `chain.from_iterable()`-Vorschlag von DasIch, weil der auch wieder ein iterierbares Objekt statt einer Sequenz liefert und damit sogar mit unendlichen Datenströmen klar kommt.