Existe uma maneira mais concisa, eficiente ou simplesmente pitônica de fazer o seguinte?
def product(list):
p = 1
for i in list:
p *= i
return p
EDITAR:
Na verdade, acho que isso é marginalmente mais rápido do 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 dá
('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
respostas aumentam aTypeError
, enquanto afor
resposta do loop retorna 1. Esse é um erro nafor
resposta do loop (o produto de uma lista vazia não é mais 1 do que 17) ou 'tatu').list
como um nome de variável ...+
desse tipo de lista (da mesma forma para product /*
). Agora percebo que o Python é digitado dinamicamente, o que dificulta as coisas, mas esse é um problema resolvido em linguagens sãs com sistemas de tipos estáticos como Haskell. MasPython
só permitesum
trabalhar com números de qualquer maneira, jásum(['a', 'b'])
que nem funciona, então eu digo novamente que0
faz sentido parasum
e1
para o produto.Respostas:
Sem usar o lambda:
é melhor e mais rápido. Com python 2.7.5
Na seguinte configuração:
Resultados com python 2.7.5
Resultado:
np.prod
é o mais rápido, se você usarnp.array
como estrutura de dados (18x para array pequeno, 250x para array grande)com python 3.3.2:
O python 3 é mais lento?
fonte
int
é Python 2long
. O Python 2 estará usando "int" até estourar 32 bits; O Python 3 usará "long" desde o início. (2) Python 3.0 foi uma "prova de conceito". Atualize para 3.1 o mais rápido possível!reduce
operador dofunctools
módulo no Python 3. IEfrom functools import reduce
.fonte
operator.mul
para obter uma maneira melhor de fazê-lo.reduce
)from functools import reduce
para fazê-lo funcionar em Python 3.se você apenas tiver números em sua lista:
EDIT : como apontado por @ off99555, isso não funciona para resultados inteiros grandes. Nesse caso, ele retorna um resultado do tipo,
numpy.int64
enquanto a solução de Ian Clelland se baseiaoperator.mul
ereduce
trabalha para resultados inteiros grandes porque retornalong
.fonte
from numpy import prod; prod(list(range(5,101)))
e saiu0
, você pode reproduzir esse resultado no Python 3?prod
retorna um resultado do tiponumpy.int64
neste caso e você recebe um estouro (um valor negativo, na verdade) járange(5,23)
. Use a solução de @Ian Clelland baseada emoperator.mul
ereduce
para números inteiros grandes (ele retorna along
nesse caso, que parece ter precisão arbitrária).np.prod(np.arange(5.0,101.0))
ou converta-a em flutuação executandonp.prod(np.array(range(5,101)).astype(np.float64))
. Observe que o NumPy usa emnp.float64
vez defloat
. Não sei a diferençaBem, se você realmente quisesse criar uma linha sem importar nada, você poderia fazer:
Mas não.
fonte
fonte
functools.reduce(..)
em python3Iniciando
Python 3.8
, umaprod
função foi incluída nomath
módulo na biblioteca padrão:que retorna o produto de um
start
valor (padrão: 1) vezes um número iterável de números:Observe que se o iterável estiver vazio, isso produzirá
1
(ou ostart
valor, se fornecido).fonte
Lembro-me de longas discussões sobre comp.lang.python (desculpe, com preguiça de produzir ponteiros agora), que concluíram que sua
product()
definição original é a mais pitonica .Observe que a proposta não é gravar um loop for toda vez que você desejar, mas escrever uma função uma vez (por tipo de redução) e chamá-la conforme necessário! Chamar funções de redução é muito Pythonic - funciona suavemente com expressões geradoras e, desde a introdução bem-sucedida de
sum()
, Python continua crescendo cada vez mais funções de redução integradas -any()
eall()
são as adições mais recentes ...Esta conclusão é meio oficial -
reduce()
foi removida dos buildins no Python 3.0, dizendo:Veja também O destino de reduzir () no Python 3000 para obter uma citação de suporte do Guido (e alguns comentários menos favoráveis de Lispers que leem esse blog).
PS se por acaso você precisar
product()
de combinatória, consultemath.factorial()
(novo 2.6).fonte
A intenção desta resposta é fornecer um cálculo que seja útil em determinadas circunstâncias - a saber, quando: a) há um grande número de valores sendo multiplicados, de modo que o produto final pode ser extremamente grande ou extremamente pequeno eb) você não realmente não me importo com a resposta exata, mas sim com várias seqüências e queremos poder solicitá-las com base no produto de cada um.
Se você deseja multiplicar os elementos de uma lista, onde l é a lista, você pode:
Agora, essa abordagem não é tão legível quanto
Se você é um matemático que não está familiarizado com reduzir (), o oposto pode ser verdadeiro, mas eu não recomendaria usá-lo em circunstâncias normais. Também é menos legível que a função product () mencionada na pergunta (pelo menos para não matemáticos).
No entanto, se você estiver em uma situação em que corre o risco de excesso ou excesso, como em
e seu objetivo é comparar os produtos de diferentes seqüências em vez de saber quais são os produtos,
é o caminho a seguir, porque é praticamente impossível ter um problema do mundo real no qual você transbordaria ou transbordaria com essa abordagem. (Quanto maior o resultado desse cálculo, maior o produto seria se você pudesse calculá-lo.)
fonte
Testei várias soluções com perfplot (um pequeno projeto meu) e descobri que
é de longe a solução mais rápida (se a lista não for muito curta).
Código para reproduzir o gráfico:
fonte
Estou surpreso que ninguém sugeriu usar
itertools.accumulate
comoperator.mul
. Isso evita o usoreduce
, que é diferente para o Python 2 e 3 (devido àfunctools
importação necessária para o Python 3) e, além disso, é considerado não-pitônico pelo próprio Guido van Rossum :Exemplo:
fonte
Uma opção é usar
numba
e o@jit
ou@njit
decorador . Também fiz um ou dois pequenos ajustes no seu código (pelo menos no Python 3, "list" é uma palavra-chave que não deve ser usada para um nome de variável):Para propósitos de tempo, você precisa executar uma vez para compilar a função primeiro usando o numba. Em geral, a função será compilada na primeira vez que for chamada e, em seguida, chamada da memória depois disso (mais rápido).
Agora, quando você executar seu código, ele será executado com a versão compilada da função. Programei-os usando um notebook Jupyter e a
%timeit
função mágica:Observe que na minha máquina, executando o Python 3.5, o
for
loop nativo do Python era realmente o mais rápido. Pode haver um truque aqui quando se trata de medir o desempenho decorado com números com os notebooks Jupyter e a%timeit
função mágica. Não tenho certeza de que os horários acima estão corretos, por isso recomendo experimentá-lo no seu sistema e ver se o numba oferece um aumento de desempenho.fonte
A maneira mais rápida que encontrei foi usando while:
e os horários são:
fonte
Resultado do Python 3 para os testes do OP: (melhor de 3 para cada)
fonte
Isso também funciona, apesar de sua trapaça
fonte
print
por um retorno. Além disso, não há necessidade de armazenar os valores intermediários em uma lista, você só precisa armazenarp
entre iterações.