Was ist der idiomatischste Weg, um in Haskell so etwas wie das Folgende zu erreichen:
foldl (+) 0 [1,2,3,4,5]
--> 15
Oder das Äquivalent in Ruby:
[1,2,3,4,5].inject(0) {|m,x| m + x}
#> 15
Offensichtlich bietet Python die reduce
Funktion, die eine Implementierung von Fold ist, genau wie oben, jedoch wurde mir gesagt, dass die "pythonische" Art der Programmierung darin bestand, lambda
Begriffe und Funktionen höherer Ordnung zu vermeiden und Listenverständnisse nach Möglichkeit zu bevorzugen. Gibt es daher eine bevorzugte Methode zum Falten einer Liste oder einer listenähnlichen Struktur in Python, die nicht die reduce
Funktion ist, oder reduce
die idiomatische Methode, um dies zu erreichen?
sum
ist nicht gut genugsum
, wenn Sie verschiedene Arten von Beispielen angeben möchten.sum()
bietet damit tatsächlich eingeschränkte Funktionalität.sum([[a], [b, c, d], [e, f]], [])
gibt[a, b, c, d, e, f]
zum Beispiel zurück.+
auf Listen ist eine lineare Zeitoperation sowohl in der Zeit als auch im Speicher, wodurch der gesamte Aufruf quadratisch wird. Die Verwendunglist(itertools.chain.from_iterable([a], [b,c,d],[e,f],[]])
ist insgesamt linear - und wenn Sie sie nur einmal durchlaufen müssen, können Sie den Anruf abbrechenlist
, um ihn in Bezug auf den Speicher konstant zu halten.Antworten:
Die pythonische Methode zum Summieren eines Arrays wird verwendet
sum
. Für andere Zwecke können Sie manchmal eine Kombination ausreduce
(aus demfunctools
Modul) und demoperator
Modul verwenden, z.Seien Sie sich bewusst, dass dies
reduce
tatsächlich einfoldl
Haskell-Begriff ist. Es gibt keine spezielle Syntax zum Ausführen von Faltungen, es gibt keine integrierte Syntaxfoldr
, und die Verwendungreduce
mit nicht assoziativen Operatoren wird als schlechter Stil angesehen.Die Verwendung von Funktionen höherer Ordnung ist ziemlich pythonisch. Es nutzt das Python-Prinzip, dass alles ein Objekt ist, einschließlich Funktionen und Klassen. Sie haben Recht, dass Lambdas von einigen Pythonisten missbilligt werden, aber hauptsächlich, weil sie nicht sehr gut lesbar sind, wenn sie komplex werden.
quelle
reduce()
ist weitgehend auf assoziative Operatoren beschränkt, und in allen anderen Fällen ist es besser, die Akkumulationsschleife explizit aufzuschreiben." Daher ist seine Verwendung begrenzt, aber selbst GvR musste offenbar zugeben, dass es nützlich genug ist, um es in der Standardbibliothek zu behalten.Haskell
foldl (+) 0 [1,2,3,4,5]
Python
reduce(lambda a,b: a+b, [1,2,3,4,5], 0)
Offensichtlich ist dies ein triviales Beispiel, um einen Punkt zu veranschaulichen. In Python würden Sie es einfach tun
sum([1,2,3,4,5])
und sogar Haskell-Puristen würden es im Allgemeinen vorziehensum [1,2,3,4,5]
.Für nicht triviale Szenarien, in denen es keine offensichtliche Komfortfunktion gibt, besteht der idiomatische pythonische Ansatz darin, die for-Schleife explizit auszuschreiben und die Zuweisung veränderlicher Variablen anstelle von
reduce
oder a zu verwendenfold
.Das ist überhaupt nicht der funktionale Stil, aber das ist der "pythonische" Weg. Python ist nicht für funktionale Puristen konzipiert. Sehen Sie, wie Python Ausnahmen für die Flusskontrolle bevorzugt, um zu sehen, wie nicht funktionsfähig idiomatisches Python ist.
quelle
In Python 3 wurde das
reduce
entfernt: Versionshinweise . Trotzdem können Sie das functools-Modul verwendenAndererseits drückt die Dokumentation die Präferenz für
for
-loop aus, anstattreduce
:quelle
reduce
wurde nicht aus der Python 3-Standardbibliothek entfernt.reduce
wie gezeigt in dasfunctools
Modul verschoben .Sie können das Rad auch neu erfinden:
quelle
f
in Ihrem rekursiven Fall um.reduce
bereits angeboten wird (beachten Sie, dass die Funktionssignatur von Reduce istreduce(function, sequence[, initial]) -> value
- es beinhaltet auch die Funktionalität, einen Anfangswert für die zu geben Akkumulator).Keine wirkliche Antwort auf die Frage, aber Einzeiler für Foldl und Foldr:
quelle
reduce(lambda y, x: x**y, reversed(a))
. Es wird jetzt natürlicher verwendet, arbeitet mit Iteratoren und verbraucht weniger Speicher.Ab
Python 3.8
dem Start und der Einführung von Zuweisungsausdrücken (PEP 572) (:=
Operator), die die Möglichkeit bieten, das Ergebnis eines Ausdrucks zu benennen, können wir ein Listenverständnis verwenden, um das zu replizieren, was andere Sprachen als Fold / Foldleft / Reduce-Operationen bezeichnen:Gegeben eine Liste, eine Reduktionsfunktion und ein Akkumulator:
wir können
items
mitf
folden, um das Ergebnis zu erhaltenaccumulation
:oder in einer kondensierten Form:
Beachten Sie, dass dies tatsächlich auch eine "Scanleft" -Operation ist, da das Ergebnis des Listenverständnisses den Zustand der Akkumulation bei jedem Schritt darstellt:
quelle
Die eigentliche Antwort auf dieses (Reduktions-) Problem lautet: Verwenden Sie einfach eine Schleife!
Dies ist schneller als eine Reduzierung und Dinge wie PyPy können solche Schleifen optimieren.
Übrigens sollte der Summenfall mit der
sum
Funktion gelöst werdenquelle
reduce
ist eine gängige Methode zur Optimierung eines Python-Programms.product
gegen eine in Ihrem Stil profiliert und sie ist schneller (allerdings geringfügig).operator.add
) als Argument zum Reduzieren: Dieser zusätzliche Aufruf ist ein C-Aufruf (der viel billiger als ein Python-Aufruf ist) und erspart das Versenden und Interpretieren einiger Bytecode-Anweisungen, die leicht Dutzende von Anweisungen verursachen können Funktionsaufrufe.Ich glaube, einige der Befragten dieser Frage haben die breitere Implikation der
fold
Funktion als abstraktes Werkzeug übersehen . Ja,sum
kann dasselbe für eine Liste von ganzen Zahlen tun, aber dies ist ein trivialer Fall.fold
ist allgemeiner. Dies ist nützlich, wenn Sie eine Folge von Datenstrukturen unterschiedlicher Form haben und eine Aggregation sauber ausdrücken möchten. Also anstatt ein aufbauen zu müssenfor
Schleife mit einer Aggregatvariablen aufzubauen und jedes Mal manuell neu zu berechnen, ermöglicht einefold
Funktion (oder die Python-Version, diereduce
zu entsprechen scheint) dem Programmierer, die Absicht der Aggregation durch einfaches Bereitstellen viel klarer auszudrücken Zwei Dinge:quelle
fold
dafür geben würden, das in Python nur schwer sauber zu machen ist, und dann "fold
" das in Python :-)Ich mag ziemlich spät zur Party kommen, aber wir können benutzerdefinierte
foldr
mit einfachen Lambda-Kalkül und Curry-Funktion erstellen . Hier ist meine Implementierung von foldr in Python.Auch wenn die Umsetzung rekursiv ist (möglicherweise langsam), werden die Werte gedruckt
15
und120
jeweilsquelle