Existe-t-il une manière plus concise, efficace ou simplement pythonique de faire ce qui suit?
def product(list):
p = 1
for i in list:
p *= i
return p
ÉDITER:
Je trouve en fait que c'est légèrement plus rapide que d'utiliser 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())
Donne moi
('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
réponses lèvent aTypeError
, alors que lafor
réponse en boucle renvoie 1. Il s'agit d'un bogue dans lafor
réponse en boucle (le produit d'une liste vide n'est pas plus 1 que 17 ou 'tatou').list
comme nom de variable ...+
ce type de liste (de même pour le produit /*
). Maintenant, je me rends compte que Python est typé dynamiquement, ce qui rend les choses plus difficiles, mais c'est un problème résolu dans des langages sains avec des systèmes de types statiques comme Haskell. MaisPython
ne permetsum
de travailler que sur les chiffres de toute façon, carsum(['a', 'b'])
cela ne fonctionne même pas, alors je répète que c'est0
logique poursum
et1
pour le produit.Réponses:
Sans utiliser lambda:
c'est mieux et plus rapide. Avec python 2.7.5
Dans la configuration suivante:
Résultats avec python 2.7.5
Résultat:
np.prod
est le plus rapide, si vous utiliseznp.array
comme structure de données (18x pour petit tableau, 250x pour grand tableau)avec python 3.3.2:
Python 3 est-il plus lent?
la source
int
est Python 2long
. Python 2 utilisera "int" jusqu'à ce qu'il déborde de 32 bits; Python 3 utilisera "long" dès le début. (2) Python 3.0 était une "preuve de concept". Passez à 3.1 dès que possible!reduce
opérateur depuis lefunctools
module dans Python 3. IEfrom functools import reduce
.la source
operator.mul
pour une meilleure façon de le faire.reduce
)from functools import reduce
pour le faire fonctionner en Python 3.si vous n'avez que des numéros dans votre liste:
EDIT : comme indiqué par @ off99555, cela ne fonctionne pas pour les grands résultats entiers, auquel cas il retourne un résultat de type
numpy.int64
tandis que la solution d'Ian Clelland basée suroperator.mul
etreduce
fonctionne pour les résultats de grands entiers car elle renvoielong
.la source
from numpy import prod; prod(list(range(5,101)))
et il est sorti0
, pouvez-vous reproduire ce résultat sur Python 3?prod
renvoie un résultat de typenumpy.int64
dans ce cas et vous obtenez déjà un débordement (une valeur négative en fait) pourrange(5,23)
. Utilisez la solution de @Ian Clelland basée suroperator.mul
etreduce
pour les grands entiers (elle renvoie along
dans ce cas qui semble avoir une précision arbitraire).np.prod(np.arange(5.0,101.0))
soit la convertir en float en faisantnp.prod(np.array(range(5,101)).astype(np.float64))
. Notez que NumPy utilise à lanp.float64
place defloat
. Je ne connais pas la différence.Eh bien, si vous vouliez vraiment en faire une ligne sans importer quoi que ce soit, vous pourriez faire:
Mais ne le faites pas.
la source
la source
functools.reduce(..)
en python3Au départ
Python 3.8
, uneprod
fonction a été intégrée aumath
module dans la bibliothèque standard:qui renvoie le produit d'une
start
valeur (par défaut: 1) fois un itérable de nombres:Notez que si l'itérable est vide, cela produira
1
(ou lastart
valeur si elle est fournie).la source
Je me souviens de quelques longues discussions sur comp.lang.python (désolé, trop paresseux pour produire des pointeurs maintenant) qui ont conclu que votre
product()
définition originale est la plus pythonique .Notez que la proposition n'est pas d'écrire une boucle for à chaque fois que vous voulez le faire, mais d'écrire une fonction une fois (par type de réduction) et de l'appeler au besoin! L'appel de fonctions de réduction est très pythonique - cela fonctionne bien avec les expressions de générateur, et depuis l'introduction réussie de
sum()
, Python continue de développer de plus en plus de fonctions de réduction intégrées -any()
etall()
sont les derniers ajouts ...Cette conclusion est un peu officielle - a
reduce()
été supprimée des fonctions intégrées de Python 3.0, en disant:Voir aussi Le sort de reduction () dans Python 3000 pour une citation de Guido (et quelques commentaires moins favorables de Lispers qui lisent ce blog).
PS si par hasard vous avez besoin
product()
de combinatoire, voirmath.factorial()
(nouveau 2.6).la source
Le but de cette réponse est de fournir un calcul qui est utile dans certaines circonstances - à savoir quand a) il y a un grand nombre de valeurs multipliées de telle sorte que le produit final peut être extrêmement grand ou extrêmement petit, et b) vous ne le faites pas ' t vraiment se soucier de la réponse exacte, mais plutôt avoir un certain nombre de séquences et vouloir pouvoir les commander en fonction du produit de chacun.
Si vous souhaitez multiplier les éléments d'une liste, où l est la liste, vous pouvez faire:
Maintenant, cette approche n'est pas aussi lisible que
Si vous êtes un mathématicien qui ne connaît pas la réduction (), le contraire peut être vrai, mais je ne conseillerais pas de l'utiliser dans des circonstances normales. Elle est également moins lisible que la fonction product () mentionnée dans la question (du moins pour les non-mathématiciens).
Cependant, si jamais vous vous trouvez dans une situation où vous risquez un sous-débordement ou un dépassement, comme dans
et votre but est de comparer les produits de différentes séquences plutôt que de savoir quels sont les produits, alors
est la voie à suivre car il est pratiquement impossible d'avoir un problème du monde réel dans lequel vous déborderiez ou déborderiez avec cette approche. (Plus le résultat de ce calcul est grand, plus le produit serait grand si vous pouviez le calculer.)
la source
J'ai testé diverses solutions avec perfplot (un de mes petits projets) et j'ai trouvé que
est de loin la solution la plus rapide (si la liste n'est pas très courte).
Code pour reproduire le tracé:
la source
Je suis surpris que personne n'ait suggéré d'utiliser
itertools.accumulate
avecoperator.mul
. Cela évite d'utiliserreduce
, qui est différent pour Python 2 et 3 (en raison de l'functools
import requis pour Python 3), et est d'ailleurs considéré comme non pythonique par Guido van Rossum lui - même :Exemple:
la source
Une option consiste à utiliser
numba
et le décorateur@jit
ou@njit
. J'ai également apporté une ou deux petites modifications à votre code (au moins en Python 3, "list" est un mot-clé qui ne doit pas être utilisé pour un nom de variable):À des fins de synchronisation, vous devez exécuter une fois pour compiler la fonction en utilisant d'abord numba. En général, la fonction sera compilée la première fois qu'elle est appelée, puis appelée à partir de la mémoire par la suite (plus rapidement).
Maintenant, lorsque vous exécutez votre code, il s'exécutera avec la version compilée de la fonction. Je les ai chronométrés à l'aide d'un notebook Jupyter et de la
%timeit
fonction magique:Notez que sur ma machine, exécutant Python 3.5, la
for
boucle native Python était en fait la plus rapide. Il peut y avoir un truc ici quand il s'agit de mesurer les performances décorées par numba avec les cahiers Jupyter et la%timeit
fonction magique. Je ne suis pas sûr que les horaires ci-dessus soient corrects, je vous recommande donc de l'essayer sur votre système et de voir si numba vous donne une amélioration des performances.la source
Le moyen le plus rapide que j'ai trouvé était d'utiliser while:
et les horaires sont:
la source
Résultat Python 3 pour les tests de l'OP: (meilleur de 3 pour chacun)
la source
Cela fonctionne aussi bien que sa triche
la source
print
par un retour. De plus, il n'est pas nécessaire de stocker les valeurs intermédiaires dans une liste, il vous suffit de stockerp
entre les itérations.