¿Existe una manera más concisa, eficiente o simplemente pitónica de hacer lo siguiente?
def product(list):
p = 1
for i in list:
p *= i
return p
EDITAR:
De hecho, encuentro que esto es marginalmente más rápido que usar 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())
me da
('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
respuestas generan unTypeError
, mientras que lafor
respuesta en bucle devuelve 1. Este es un error en lafor
respuesta en bucle (el producto de una lista vacía no es más de 1 que 17 o 'armadillo').list
como nombre de variable ...+
para ese tipo de lista (del mismo modo para producto /*
). Ahora me doy cuenta de que Python está tipeado dinámicamente, lo que dificulta las cosas, pero este es un problema resuelto en idiomas sanos con sistemas de tipo estático como Haskell. Pero de todos modosPython
solo permitesum
trabajar en números, yasum(['a', 'b'])
que ni siquiera funciona, por lo que nuevamente digo que0
tiene sentido parasum
y1
para el producto.Respuestas:
Sin usar lambda:
Es mejor y más rápido. Con python 2.7.5
En la siguiente configuración:
Resultados con python 2.7.5
Resultado:
np.prod
es el más rápido, si lo utilizanp.array
como estructura de datos (18x para matriz pequeña, 250x para matriz grande)con python 3.3.2:
¿Python 3 es más lento?
fuente
int
es Python 2long
. Python 2 usará "int" hasta que se desborde 32 bits; Python 3 usará "largo" desde el principio. (2) Python 3.0 era una "prueba de concepto". ¡Actualice a 3.1 CUANTO ANTES!reduce
operador desde elfunctools
módulo en Python 3. IEfrom functools import reduce
.fuente
operator.mul
una mejor manera de hacerlo.reduce
)from functools import reduce
para que funcione en Python 3.si solo tienes números en tu lista:
EDITAR : como señaló @ off99555, esto no funciona para resultados enteros grandes, en cuyo caso devuelve un resultado de tipo,
numpy.int64
mientras que la solución de Ian Clelland se basaoperator.mul
yreduce
funciona para resultados enteros grandes porque devuelvelong
.fuente
from numpy import prod; prod(list(range(5,101)))
y salió0
, ¿puedes reproducir este resultado en Python 3?prod
devuelve un resultado de tiponumpy.int64
en este caso y ya obtienes un desbordamiento (un valor negativo en realidad)range(5,23)
. Utilice la solución de @Ian Clelland basada enoperator.mul
yreduce
para enteros grandes (devuelve unlong
en este caso que parece tener una precisión arbitraria).np.prod(np.arange(5.0,101.0))
o convertirla en flotante haciendonp.prod(np.array(range(5,101)).astype(np.float64))
. Tenga en cuenta que NumPy usa ennp.float64
lugar defloat
. No se la diferencia.Bueno, si realmente quisieras hacer una línea sin importar nada, podrías hacer:
Pero no lo hagas.
fuente
fuente
functools.reduce(..)
en python3Comenzando
Python 3.8
,prod
se ha incluido una función almath
módulo en la biblioteca estándar:que devuelve el producto de un
start
valor (predeterminado: 1) multiplicado por un iterable de números:Tenga en cuenta que si el iterable está vacío, esto producirá
1
(o elstart
valor si se proporciona).fuente
Recuerdo algunas largas discusiones sobre comp.lang.python (lo siento, demasiado flojo para producir punteros ahora) que concluyeron que su
product()
definición original es la más Pythonic .Tenga en cuenta que la propuesta no es escribir un bucle for cada vez que quiera hacerlo, sino escribir una función una vez (por tipo de reducción) y llamarla según sea necesario. Llamar a las funciones de reducción es muy Pythonic: funciona muy bien con las expresiones generadoras y, desde la introducción exitosa
sum()
, Python sigue creciendo cada vez más funciones de reducción incorporadas,any()
yall()
son las últimas incorporaciones ...Esta conclusión es un poco oficial:
reduce()
se eliminó de las incorporaciones en Python 3.0, diciendo:Consulte también El destino de reduce () en Python 3000 para obtener una cita de apoyo de Guido (y algunos comentarios de menos apoyo de Lispers que leyeron ese blog).
PD: si por casualidad necesitas
product()
combinatoria, vermath.factorial()
(nuevo 2.6).fuente
La intención de esta respuesta es proporcionar un cálculo que sea útil en ciertas circunstancias, es decir, cuando a) se multiplique una gran cantidad de valores de manera que el producto final pueda ser extremadamente grande o extremadamente pequeño, yb) usted no ' Realmente no me importa la respuesta exacta, sino que tiene una serie de secuencias y quiero poder ordenarlas en función del producto de cada uno.
Si desea multiplicar los elementos de una lista, donde l es la lista, puede hacer lo siguiente:
Ahora, ese enfoque no es tan legible como
Si eres un matemático que no está familiarizado con reduce (), lo contrario podría ser cierto, pero no recomendaría usarlo en circunstancias normales. También es menos legible que la función producto () mencionada en la pregunta (al menos para los no matemáticos).
Sin embargo, si alguna vez se encuentra en una situación en la que corre el riesgo de desbordamiento o desbordamiento, como en
y su propósito es comparar los productos de diferentes secuencias en lugar de saber cuáles son los productos, luego
es el camino a seguir porque es prácticamente imposible tener un problema del mundo real en el que se desborde o desborde con este enfoque. (Cuanto mayor sea el resultado de ese cálculo, mayor será el producto si pudiera calcularlo).
fuente
He probado varias soluciones con perfplot (un pequeño proyecto mío) y descubrí que
es, con mucho, la solución más rápida (si la lista no es muy corta).
Código para reproducir la trama:
fuente
Me sorprende que nadie haya sugerido usar
itertools.accumulate
conoperator.mul
. Esto evita el usoreduce
, que es diferente para Python 2 y 3 (debido a lafunctools
importación requerida para Python 3), y además el propio Guido van Rossum lo considera antipitónico :Ejemplo:
fuente
Una opción es usar
numba
y el@jit
o@njit
decorador . También hice uno o dos pequeños ajustes a su código (al menos en Python 3, "lista" es una palabra clave que no debe usarse para un nombre de variable):Para fines de temporización, debe ejecutar una vez para compilar la función primero usando numba. En general, la función se compilará la primera vez que se llame y luego se llamará desde la memoria (más rápido).
Ahora, cuando ejecute su código, se ejecutará con la versión compilada de la función. Los cronometré usando un cuaderno Jupyter y la
%timeit
función mágica:Tenga en cuenta que en mi máquina, ejecutando Python 3.5, el
for
bucle nativo de Python fue en realidad el más rápido. Puede haber un truco aquí cuando se trata de medir el rendimiento decorado con numba con los portátiles Jupyter y la%timeit
función mágica. No estoy seguro de que los tiempos anteriores sean correctos, por lo que recomiendo probarlo en su sistema y ver si numba le brinda un aumento de rendimiento.fuente
La forma más rápida que encontré fue, usando while:
y los horarios son:
fuente
Resultado de Python 3 para las pruebas de OP: (el mejor de 3 para cada uno)
fuente
Esto también funciona a pesar de su trampa
fuente
print
con un retorno. Además, no es necesario almacenar los valores intermedios en una lista, solo necesita almacenarp
entre iteraciones.