Gibt es eine präzisere, effizientere oder einfach pythonischere Möglichkeit, Folgendes zu tun?
def product(list):
p = 1
for i in list:
p *= i
return p
BEARBEITEN:
Ich finde tatsächlich, dass dies geringfügig schneller ist als die Verwendung von operator.mul:
from operator import mul
# from functools import reduce # python3 compatibility
def with_lambda(list):
reduce(lambda x, y: x * y, list)
def without_lambda(list):
reduce(mul, list)
def forloop(list):
r = 1
for x in list:
r *= x
return r
import timeit
a = range(50)
b = range(1,50)#no zero
t = timeit.Timer("with_lambda(a)", "from __main__ import with_lambda,a")
print("with lambda:", t.timeit())
t = timeit.Timer("without_lambda(a)", "from __main__ import without_lambda,a")
print("without lambda:", t.timeit())
t = timeit.Timer("forloop(a)", "from __main__ import forloop,a")
print("for loop:", t.timeit())
t = timeit.Timer("with_lambda(b)", "from __main__ import with_lambda,b")
print("with lambda (no 0):", t.timeit())
t = timeit.Timer("without_lambda(b)", "from __main__ import without_lambda,b")
print("without lambda (no 0):", t.timeit())
t = timeit.Timer("forloop(b)", "from __main__ import forloop,b")
print("for loop (no 0):", t.timeit())
gibt mir
('with lambda:', 17.755449056625366)
('without lambda:', 8.2084708213806152)
('for loop:', 7.4836349487304688)
('with lambda (no 0):', 22.570688009262085)
('without lambda (no 0):', 12.472226858139038)
('for loop (no 0):', 11.04065990447998)
reduce
Antworten a auslösenTypeError
, während diefor
Schleifenantwort 1 zurückgibt. Dies ist ein Fehler in derfor
Schleifenantwort (das Produkt einer leeren Liste ist nicht mehr 1 als 17 oder "Gürteltier").list
als Variablenname verwendet wird ...+
für diesen Listentyp ist (ebenfalls für product /*
). Jetzt ist mir klar, dass Python dynamisch typisiert ist, was die Sache schwieriger macht, aber dies ist ein gelöstes Problem in vernünftigen Sprachen mit statischen Typsystemen wie Haskell. AberPython
erlaubtsum
sowieso nur , an Zahlen zu arbeiten, dasum(['a', 'b'])
es nicht einmal funktioniert, also sage ich noch einmal, dass0
das fürsum
und1
für das Produkt Sinn macht .Antworten:
Ohne Lambda:
es ist besser und schneller. Mit Python 2.7.5
In der folgenden Konfiguration:
Ergebnisse mit Python 2.7.5
Ergebnis:
np.prod
ist das schnellste, wenn Sie esnp.array
als Datenstruktur verwenden (18x für kleines Array, 250x für großes Array)mit Python 3.3.2:
Ist Python 3 langsamer?
quelle
int
ist Python 2long
. Python 2 verwendet "int", bis 32 Bit überlaufen. Python 3 wird von Anfang an "long" verwenden. (2) Python 3.0 war ein "Proof of Concept". Upgrade auf 3.1 so schnell wie möglich!reduce
Operator aus demfunctools
Modul in Python 3 importieren müssen . IEfrom functools import reduce
.quelle
operator.mul
für einen besseren Weg, dies zu tun.reduce
)from functools import reduce
, damit es in Python 3Wenn Sie nur Zahlen in Ihrer Liste haben:
BEARBEITEN : Wie von @ off99555 hervorgehoben, funktioniert dies nicht für Ergebnisse mit großen Ganzzahlen. In diesem Fall wird ein Ergebnis vom Typ zurückgegeben,
numpy.int64
während Ian Clellands Lösung auf Ergebnissen mit großen Ganzzahlen basiertoperator.mul
undreduce
für diese Ergebnisse funktioniert, da sie zurückgegeben wirdlong
.quelle
from numpy import prod; prod(list(range(5,101)))
und es wurde ausgegeben. Können0
Sie dieses Ergebnis auf Python 3 reproduzieren?prod
ein Ergebnis vom Typ zurückgibtnumpy.int64
und Sie bereits einen Überlauf (tatsächlich einen negativen Wert) für erhaltenrange(5,23)
. Verwenden Sie die @ Ian Clelland-Lösung, die aufoperator.mul
undreduce
für große Ganzzahlen basiert (long
in diesem Fall wird eine zurückgegeben, die eine willkürliche Genauigkeit zu haben scheint).np.prod(np.arange(5.0,101.0))
oder konvertieren Sie sie mit einer Float-Typ-Listenp.prod(np.array(range(5,101)).astype(np.float64))
. Beachten Sie, dass NumPynp.float64
anstelle von verwendetfloat
. Ich kenne den Unterschied nicht.Nun, wenn Sie wirklich eine Zeile erstellen möchten, ohne etwas zu importieren, können Sie Folgendes tun:
Aber nicht.
quelle
quelle
functools.reduce(..)
in python3Ab dem Start
Python 3.8
wurde eineprod
Funktion in dasmath
Modul in der Standardbibliothek aufgenommen:Dies gibt das Produkt eines
start
Wertes (Standard: 1) mal einer iterierbaren Zahl zurück:Beachten Sie, dass wenn die Iterable leer ist, dies erzeugt
1
(oder denstart
Wert, falls angegeben).quelle
Ich erinnere mich an einige lange Diskussionen über comp.lang.python (sorry, zu faul, um jetzt Zeiger zu erstellen), die zu dem Schluss kamen, dass Ihre ursprüngliche
product()
Definition die pythonischste ist .Beachten Sie, dass der Vorschlag nicht darin besteht, jedes Mal eine for-Schleife zu schreiben, sondern eine Funktion einmal (pro Reduktionsart) zu schreiben und sie nach Bedarf aufzurufen! Das Aufrufen von Reduktionsfunktionen ist sehr pythonisch - es funktioniert hervorragend mit Generatorausdrücken, und seit der erfolgreichen Einführung von
sum()
Python werden immer mehr integrierte Reduktionsfunktionen entwickelt -any()
undall()
es handelt sich um die neuesten Ergänzungen ...Diese Schlussfolgerung ist ein bisschen offiziell -
reduce()
wurde aus den in Python 3.0 integrierten Funktionen entfernt und lautet:Siehe auch Das Schicksal von redu () in Python 3000 für ein unterstützendes Zitat von Guido (und einige weniger unterstützende Kommentare von Lispers, die diesen Blog lesen).
PS Wenn Sie zufällig
product()
Kombinatorik benötigen , siehemath.factorial()
(neu 2.6).quelle
Mit dieser Antwort soll eine Berechnung bereitgestellt werden, die unter bestimmten Umständen nützlich ist - nämlich wenn a) eine große Anzahl von Werten so multipliziert wird, dass das Endprodukt extrem groß oder extrem klein sein kann, und b) Sie dies nicht tun. Ich kümmere mich nicht wirklich um die genaue Antwort, sondern habe stattdessen eine Reihe von Sequenzen und möchte sie basierend auf dem jeweiligen Produkt bestellen können.
Wenn Sie die Elemente einer Liste multiplizieren möchten, wobei l die Liste ist, können Sie Folgendes tun:
Dieser Ansatz ist nicht so lesbar wie
Wenn Sie ein Mathematiker sind, der mit redu () nicht vertraut ist, ist das Gegenteil der Fall, aber ich würde nicht empfehlen, es unter normalen Umständen zu verwenden. Es ist auch weniger lesbar als die in der Frage erwähnte Funktion product () (zumindest für Nicht-Mathematiker).
Wenn Sie sich jedoch jemals in einer Situation befinden, in der Sie einen Unter- oder Überlauf riskieren, z
und Ihr Zweck ist es, die Produkte verschiedener Sequenzen zu vergleichen, anstatt zu wissen, was die Produkte sind
Dies ist der richtige Weg, da es praktisch unmöglich ist, ein reales Problem zu haben, bei dem Sie mit diesem Ansatz über- oder unterlaufen würden. (Je größer das Ergebnis dieser Berechnung ist, desto größer wäre das Produkt, wenn Sie es berechnen könnten .)
quelle
Ich habe verschiedene Lösungen mit perfplot (einem kleinen Projekt von mir) getestet und festgestellt, dass
ist bei weitem die schnellste Lösung (wenn die Liste nicht sehr kurz ist).
Code zur Reproduktion der Handlung:
quelle
Ich bin überrascht, dass niemand vorgeschlagen hat, mit
itertools.accumulate
zu verwendenoperator.mul
. Dies vermeidet die Verwendungreduce
, die für Python 2 und 3 unterschiedlich ist (aufgrund desfunctools
für Python 3 erforderlichen Imports), und wird außerdem von Guido van Rossum selbst als nicht-pythonisch angesehen :Beispiel:
quelle
Eine Option ist die Verwendung von
numba
und@jit
oder@njit
Dekorateur . Ich habe auch ein oder zwei kleine Änderungen an Ihrem Code vorgenommen (zumindest in Python 3 ist "list" ein Schlüsselwort, das nicht für einen Variablennamen verwendet werden sollte):Aus Timing-Gründen müssen Sie einmal ausführen, um die Funktion zuerst mit numba zu kompilieren. Im Allgemeinen wird die Funktion beim ersten Aufruf kompiliert und danach (schneller) aus dem Speicher aufgerufen.
Wenn Sie jetzt Ihren Code ausführen, wird er mit der kompilierten Version der Funktion ausgeführt. Ich habe sie mit einem Jupyter-Notizbuch und der
%timeit
magischen Funktion zeitlich festgelegt :Beachten Sie, dass auf meinem Computer mit Python 3.5 die native Python-
for
Schleife tatsächlich die schnellste war. Hier kann es einen Trick geben, wenn es darum geht, die Leistung von numba-dekorierten Jupyter-Notebooks und die%timeit
magische Funktion zu messen . Ich bin mir nicht sicher, ob die oben genannten Timings korrekt sind. Ich empfehle daher, sie auf Ihrem System auszuprobieren und zu prüfen, ob Sie mit numba einen Leistungsschub erzielen.quelle
Der schnellste Weg, den ich gefunden habe, war, while zu verwenden:
und die Zeiten sind:
quelle
Python 3-Ergebnis für die OP-Tests: (jeweils das Beste aus 3)
quelle
Dies funktioniert auch durch Betrug
quelle
print
durch eine Rückgabe ersetzen . Außerdem müssen die Zwischenwerte nicht in einer Liste gespeichert werden,p
sondern nur zwischen den Iterationen.