Guter Weg um "Skalar" an eine Liste zu addieren

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.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dienstag 17. März 2009, 01:03

Hallo,

ich habe heute mal ein wenig mit dem itertools- und operator-Modulen rumgespielt und habe da auch einiges realisieren können, aber für folgendes Problem fällt mir keine gute Lösung ein.

Ich möchte gerne eine Art Skalar mit einer Operation auf eine Liste anwenden, in etwa so:

Code: Alles auswählen

In [1]: import operator as op

In [2]: l = [1, 2, 3]

In [3]: skalar = 6

In [5]: from itertools import imap

In [6]: list(imap(op.add, [skalar]*3, l))
Out[6]: [7, 8, 9]
Das ist irgend wie nicht wirklich "hübsch", da ich die "3" kennen muss und außerdem eine neue Liste erzeugt wird.

Wäre für nen Tipp dankbar!
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 17. März 2009, 01:14

Was du suchst sind partielle Funktionen, auch bekannt als Currying oder auf deutsch Schönfinkeln:

Code: Alles auswählen

from functools import partial
from operator import add
from itertools import imap

l = [1, 2, 3]
print list(imap(partial(add, 6), l))
Damit erstellst du quasi eine unäre Funktion bei dem ein Argument schon festgelegt wird. Du kannst dir auch die Folien vom 20. Usertreffen in München ansehen, dort gibt es zwei Beispiele dazu.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dienstag 17. März 2009, 01:21

Ich danke Dir! Dieses "partial" habe ich bisher nicht verstanden - aber ich werde mir die Folien mal angucken; beim "Unicode"-Ärger haben sie mir damals (14. Treffen?) auch sehr geholfen!

Ich glaube wenn man die itertools- und functools-Module verstanden hat, kann man viele Dinge wesentlich eleganter ausdrücken in Python!
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Dienstag 17. März 2009, 01:31

Code: Alles auswählen

>>> import operator as op
>>> l = [1, 2, 3]
>>> skalar = 6
>>> from itertools import imap
>>> list(imap(lambda x: op.add(x, skalar), l))
[7, 8, 9]
Was spricht dagegen o_o? Wahrscheinlcih denk ich zu ... meh, doof.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dienstag 17. März 2009, 01:49

BlackVivi hat geschrieben: Was spricht dagegen o_o? Wahrscheinlcih denk ich zu ... meh, doof.
Ich denke das ist genau eines der lambdas, von denen Leonidas in seinen Folien spricht ;-)
DasIch
User
Beiträge: 2465
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dienstag 17. März 2009, 02:02

@BlackVivi partial gibt es genau dafür, dann sollte man kein lambda verwenden. Vorallem weil lambda recht beschrenkt im Gegensatz zu partial.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Dienstag 17. März 2009, 09:05

Gerade erst an imap gewöhnt und jetzt schon py3 ... Wie sähe eigentlich eine 3.x-Lösung ohne imap aus?

Gruß,
Christian

PS Erwähnte ich schon numpy? *duck* :wink:
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Dienstag 17. März 2009, 09:23

Wenn ich das richtig verstanden habe verhält sich map() ab Python3.x wie vorher imap().
Oder übersehe ich da jetzt was?!
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Dienstag 17. März 2009, 09:53

Sieht in der Tat so aus:

Code: Alles auswählen

help(map)
in 3.0 ergibt:

Code: Alles auswählen

Help on class map in module builtins:

class map(object)
 |  map(func, *iterables) --> map object
 |  
 |  Make an iterator that computes the function using arguments from
 |  each of the iterables.  Stops when the shortest iterable is exhausted.
:oops:
Danke,
Christian
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 17. März 2009, 10:53

Man muss sich einfach vorstellen dass die ``i``-Varianten der ``itertools`` zum Standard werden. Daher habe ich im Beispiel oben auch ``imap`` und ``list`` verwendet, wo auch ein normales ``map`` gereicht hätte.

Zum Thema ``partial``: das ist generell ein recht interessantes Thema. In Python kann es verwendet werden um positionelle Argumente zu setzen, mit dem linken startend. Das entspricht wie ich erst vor paar Tagen festgestellt habe, ``curry`` in Scheme. Weiterhin nimmt Pythons ``partial`` auch Keyword-Argumente (siehe auch das Beispiel in meinen Folien, da wird das verwendet), so dass man auch die Möglichkeit hat die Funktions-Parameter von rechts aufzufüllen (in Scheme macht man das mit ``curryr``, was aber eigentlich nicht so flexibel ist). Wozu man das braucht? Nun, ich wollte aus einer aufsteigenden Zahlenreihe (xrange) Zyklen von 0 bis 4 machen, also jedes Element Modulo 5 rechnen. Mit ``partial(mod, 5)`` bekommt man aber ``5 % zahl``. Somit kann man sich hier mit ``partial(mod, b=5)`` abhelfen, wo dann ``zahl % 5`` rauskommt.

Ein weitere nette Anwendung von Currying sind funktionale Sprachen die nur Funktionen mit einem Argument haben. Ich meine dass da Haskell dazugehört, denn dort ist ein ``add = lambda a, b: a+b`` ein ``add = lambda b: lambda a: a+b``. Dies bedeutet, dass wenn man dieser Funktion keine zwei Parameter sondern nur einen mitgibt, man automatisch so eine partielle Funktion bekommt: ``add(5)`` ist dann ``lambda a: a+5`` und wenn man ``add(5)(1)`` ausführt dann bekommt man regulär 6 als Ergebnis. Natürlich gibt es dafür syntaktischen Zucker, man muss seine Funktionen nicht selbst verschachteln :)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
DasIch
User
Beiträge: 2465
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dienstag 17. März 2009, 14:05

@Leonidas Stimmt Haskell gehört dazu.

Code: Alles auswählen

Prelude> let add a b = a + b
Prelude> let foo = add 1
Prelude> foo 2
3
Prelude> :type add
add :: (Num a) => a -> a -> a
Prelude> :type foo
foo :: Integer -> Integer
Man sieht dass am Typ der Funktion.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Mittwoch 25. März 2009, 01:39

Code: Alles auswählen

In [6]: op.add(3, b=5)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/media/Daten/Projects/Qadesh/<ipython console> in <module>()

TypeError: add() takes no keyword arguments
Hat das irgendeinen guten Grund? (Python 2.5.4)

Das hier:
Mit ``partial(mod, 5)`` bekommt man aber ``5 % zahl``. Somit kann man sich hier mit ``partial(mod, b=5)`` abhelfen, wo dann ``zahl % 5`` rauskommt.
musste ich eigentlich mit op.add selbst anwenden und funktioniert auch nicht, gleiche Fehlermeldung (mit add statt mod). Das heißt, partial() an sich funktioniert natürlich schon, kracht dann aber beim Aufruf. Hmpf, behelf ich mir mit lambda.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 25. März 2009, 09:23

Lass halt die Keyword-Argumente weg, Addition ist ja kommutativ also muss du nicht einen spezielles Argument belegen, es reicht ja nur dass eines von beiden belegt wird.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Mittwoch 25. März 2009, 14:14

Integer Addition: Ja, Tupel Addition: Nein. Auf die Idee wär ich sonst auch gekommen ;P Obwohl, ich hätte vielleicht nicht grade Zahlen zum Testen nehmen sollen und das ohne weiteren Kommentar hier posten sollen. Dennoch kann das wohl nur eine Beschränkung des operator Modules sein, welches in C geschrieben ist (bzw zumindest wird dann eine operator.so geladen). Nur die Frage, warum.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 25. März 2009, 16:02

DasIch hat geschrieben:Stimmt Haskell gehört dazu.
Gut das bestätigt bekommen. In Scheme kann man das über Makros nachrüsten :)

@str1442: Tatsache, soweit hab ich nicht gedacht :oops:. Ich kann dir auch nicht sagen warum das so ist; ich würde sagen, dass das so nicht sein sollte. Vielleicht kann man ja ein Ticket deswegen aufmachen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Antworten