Comment puis-je multiplier tous les éléments d'une liste avec Python?


204

J'ai besoin d'écrire une fonction qui prend une liste de nombres et les multiplie . Exemple: [1,2,3,4,5,6]me donnera 1*2*3*4*5*6. Je pourrais vraiment utiliser votre aide.

Réponses:


208

Python 3: utilisez functools.reduce:

>>> from functools import reduce
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720

Python 2: utilisez reduce:

>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720

Pour une utilisation compatible avec 2 et 3 pip install six, alors:

>>> from six.moves import reduce
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720

Vous n'importez pas d'opérateur, cette solution est donc un peu plus compacte. Je me demande laquelle est la plus rapide.
bloqué le

30
@jheld: J'ai chronométré la production des nombres de 1 à 100. En python2 et 3, j'ai lambdapris une moyenne de 0,02 s / 1000 répétitions, alors que operator.mulj'ai pris une moyenne de 0,009 s / 1000 répétitions, ce qui rend operator.mulun ordre de grandeur plus rapide.
whereeswalden

4
@wordsforthewise c'est probablement que passer par une fonction supplémentaire (lambda) ajoute des frais généraux, tandis que operator.mulva directement à C.
whereeswalden

4
Je n'appellerais vraiment pas .009 un ordre de grandeur inférieur à .02. C'est à peu près la moitié.
jlh

1
Depuis Python 3.8, cela peut être fait simplement avec math.prod([1,2,3,4,5,6]). (nécessite bien sûr l'importation)
Tomerikoo

168

Vous pouvez utiliser:

import operator
import functools
functools.reduce(operator.mul, [1,2,3,4,5,6], 1)

Voir reduceet operator.muldocumentations pour une explication.

Vous avez besoin de la import functoolsligne en Python 3+.


32
Notez qu'en python3, la reduce()fonction a été supprimée de l'espace de noms global et placée dans le functoolsmodule. Donc, en python3, vous devez dire from functools import reduce.
Eugene Yarmash

2
Le «1» comme troisième argument n'est pas nécessaire ici, quel est le cas où il serait nécessaire?
wordsforthewise

5
@wordsforthewise sans le troisième argument, il lève une exception TypeError si vous lui passez une séquence vide
Francisco Couzo

1
lambda x,y: x*yfonctionne également au lieu deoperator.mul

79

J'utiliserais le numpy.prodpour effectuer la tâche. Voir ci-dessous.

import numpy as np
mylist = [1, 2, 3, 4, 5, 6] 
result = np.prod(np.array(mylist))  

13
Pratique si vous utilisez déjà Numpy. Vous n'avez probablement même pas besoin de le diffuser en tant que liste en premier, cela devrait fonctionner dans la plupart des casresult = np.prod(mylist)
Nick

4
Deux choses à surveiller: 1) Il pourrait déborder, surtout si vous utilisez la valeur numpy.int32par défaut comme ci-dessus 2) Pour les petites listes, cela sera considérablement plus lent, car NumPy doit allouer un tableau (pertinent s'il est répété souvent)
Désenchanté

1
débordement pour les valeurs supérieures à 21 icinp.prod(np.array(range(1,21)))
PatrickT

Ce n'est pas un bon choix. Il peut déborder et il est plus lent. essayez reduce.
Peyman

57

Si vous voulez éviter d'importer quoi que ce soit et éviter les zones plus complexes de Python, vous pouvez utiliser une boucle for simple

product = 1  # Don't use 0 here, otherwise, you'll get zero 
             # because anything times zero will be zero.
list = [1, 2, 3]
for x in list:
    product *= x

7
Remarque mineure: les tranches en Python sont très faciles, et comme nous ne traitons ici que des primitives, vous pouvez éviter le petit souci de commencer par 1 en commençant par la liste [0] et en itérant sur la liste [1:]. Bien que se familiariser avec les réponses plus réduites plus fonctionnelles ici soit utile à long terme car il est également utile dans d'autres circonstances.
kungphu

@kungphu Le produit vide est généralement défini comme 1, votre solution lèverait une exception IndexError à la place si vous lui passez une séquence vide
Francisco Couzo

@Francisco Accordé, mais cette fonction devrait probablement jeter une saveur d'exception dans ce cas, car une séquence vide serait une entrée non valide pour cette fonction. En fait, cette fonction n'est significative pour aucune séquence de moins de deux valeurs; si vous passez une séquence avec une valeur et la multipliez par 1, vous avez essentiellement ajouté une valeur qui n'était pas là, ce qui, je dirais, équivaut à un comportement inattendu.
kungphu

1
@kungphu, le comportement de cette réponse est correct, c'est-à-dire que le fait de passer une liste de longueur 1 renvoie la valeur et de passer une liste de longueur 0 renvoie 1. C'est dans la même ligne de pensée qui donne la somme ([]) comme 0 ou la somme ([3]) comme 3. Voir: en.wikipedia.org/wiki/Empty_product
emorris

Je vois votre point concernant les fonctions mathématiques. Cependant, dans une situation de développement pratique, je l'appellerais une situation très rare où une fonction explicitement destinée à fonctionner sur une entrée devrait renvoyer une valeur étant donné ce qui équivaut à aucune entrée ou entrée non valide. Je suppose que cela dépend du but de l'exercice: si c'est juste pour répliquer la bibliothèque standard, OK, peut-être que cela apprend aux gens comment le (ou un) langage est ou peut être implémenté. Sinon, je dirais qu'il manque une bonne occasion de donner une leçon sur des arguments valides et invalides.
kungphu

14

Au démarrage Python 3.8, une .prodfonction a été intégrée au mathmodule dans la bibliothèque standard:

math.prod(iterable, *, start=1)

La méthode renvoie le produit d'une startvaleur (par défaut: 1) multipliée par un itérable de nombres:

import math
math.prod([1, 2, 3, 4, 5, 6])

>>> 720

Si l'itérable est vide, cela produira 1(ou la startvaleur, si elle est fournie).


10

Voici quelques mesures de performances de ma machine. Pertinent dans le cas où cela est effectué pour de petites entrées dans une boucle longue:

import functools, operator, timeit
import numpy as np

def multiply_numpy(iterable):
    return np.prod(np.array(iterable))

def multiply_functools(iterable):
    return functools.reduce(operator.mul, iterable)

def multiply_manual(iterable):
    prod = 1
    for x in iterable:
        prod *= x

    return prod

sizesToTest = [5, 10, 100, 1000, 10000, 100000]

for size in sizesToTest:
    data = [1] * size

    timerNumpy = timeit.Timer(lambda: multiply_numpy(data))
    timerFunctools = timeit.Timer(lambda: multiply_functools(data))
    timerManual = timeit.Timer(lambda: multiply_manual(data))

    repeats = int(5e6 / size)
    resultNumpy = timerNumpy.timeit(repeats)
    resultFunctools = timerFunctools.timeit(repeats)
    resultManual = timerManual.timeit(repeats)
    print(f'Input size: {size:>7d} Repeats: {repeats:>8d}    Numpy: {resultNumpy:.3f}, Functools: {resultFunctools:.3f}, Manual: {resultManual:.3f}')

Résultats:

Input size:       5 Repeats:  1000000    Numpy: 4.670, Functools: 0.586, Manual: 0.459
Input size:      10 Repeats:   500000    Numpy: 2.443, Functools: 0.401, Manual: 0.321
Input size:     100 Repeats:    50000    Numpy: 0.505, Functools: 0.220, Manual: 0.197
Input size:    1000 Repeats:     5000    Numpy: 0.303, Functools: 0.207, Manual: 0.185
Input size:   10000 Repeats:      500    Numpy: 0.265, Functools: 0.194, Manual: 0.187
Input size:  100000 Repeats:       50    Numpy: 0.266, Functools: 0.198, Manual: 0.185

Vous pouvez voir que Numpy est un peu plus lent sur les petites entrées, car il alloue un tableau avant la multiplication. Faites également attention au débordement dans Numpy.


Vous pouvez ajouter la méthode eval juste par curiosité
Mr_and_Mrs_D

Je soupçonne que multiply_functoolset multiply_numpy sont alourdis par avoir à regarder les np, functoolset operatorglobals, suivi par des attributs lookups. Pourriez-vous passer aux locaux? _reduce=functools.reduce, _mul = operator.mul` dans la signature de fonction puis return _reduce(_mul, iterable)dans le corps, etc.
Martijn Pieters

1
De plus, la version numpy doit d'abord convertir les nombres en un tableau numpy; vous auriez normalement déjà effectué cette conversion, l'inclure dans les horaires n'est pas vraiment juste. Avec la liste convertie en un tableau numpy une fois, l' np.prod()option démarre devient plus rapide à 100 éléments ou plus.
Martijn Pieters

8

Personnellement, j'aime cela pour une fonction qui multiplie tous les éléments d'une liste générique:

def multiply(n):
    total = 1
    for i in range(0, len(n)):
        total *= n[i]
    print total

Il est compact, utilise des choses simples (une variable et une boucle for) et me semble intuitif (il ressemble à ce que je penserais du problème, il suffit d'en prendre un, de le multiplier, puis de multiplier par le suivant, et ainsi de suite! )


3
génial, c'est le plus simple et le plus simple.
ghostkraviz

4
for i in n:Alors pourquoi pas total *= i? ne serait-ce pas beaucoup plus simple?
Munim Munna

@MunimMunnaIt n'a pas fonctionné pour moi comme ci-dessus.
athul

5

La manière la plus simple est:

import numpy as np
np.exp(np.log(your_array).sum())

10
qu'en est-il justenp.prod(your_Array)
dashesy

3

Numpya la prod()fonction qui retourne le produit d'une liste, ou dans ce cas puisque c'est numpy, c'est le produit d'un tableau sur un axe donné:

import numpy
a = [1,2,3,4,5,6]
b = numpy.prod(a)

... ou bien vous pouvez simplement importer numpy.prod():

from numpy import prod
a = [1,2,3,4,5,6]
b = prod(a)

2

J'ai trouvé cette question aujourd'hui mais j'ai remarqué qu'elle n'a pas le cas où il y en a Nonedans la liste. Ainsi, la solution complète serait:

from functools import reduce

a = [None, 1, 2, 3, None, 4]
print(reduce(lambda x, y: (x if x else 1) * (y if y else 1), a))

En cas d'addition, nous avons:

print(reduce(lambda x, y: (x if x else 0) + (y if y else 0), a))

2
nums = str(tuple([1,2,3]))
mul_nums = nums.replace(',','*')
print(eval(mul_nums))

5
Veuillez ajouter quelques explications à votre réponse. Comment répondre
xenteros

3
J'interviens et j'explique le code: personnellement, j'aime peu ce code, car il utilise eval, qui interprète la chaîne comme un argument ou une fonction (et est donc généralement considéré comme une chose dangereuse à faire, en particulier lors de la manipulation des données d'entrée ). La ligne qui précède remplace chaque virgule de délimitation par un multiplicatif *, de sorte que eval le reconnaîtra comme un multiplicatif. Je me demande quelles sont les performances sur ce point, en particulier par rapport à d'autres solutions
dennlinger

Wow, une si mauvaise idée!
Kowalski

1

Je voudrais cela de la manière suivante:

    def product_list(p):
          total =1 #critical step works for all list
          for i in p:
             total=total*i # this will ensure that each elements are multiplied by itself
          return total
   print product_list([2,3,4,2]) #should print 48

1

Voici mon code:

def product_list(list_of_numbers):
    xxx = 1
    for x in list_of_numbers:
        xxx = xxx*x
    return xxx

print(product_list([1,2,3,4]))

résultat: ('1 * 1 * 2 * 3 * 4', 24)


0

Que diriez-vous d'utiliser la récursivité?

def multiply(lst):
    if len(lst) > 1:
        return multiply(lst[:-1])* lst[-1]
    else:
        return lst[0]

-1

Ma solution:

def multiply(numbers):
    a = 1
    for num in numbers:
        a *= num
        return a

  pass

-1

'' 'la seule méthode simple pour comprendre l'utilisation logique de la boucle' ''

Lap = [2,5,7,7,9] x = 1 pour i in Lap: x = i * x print (x)


Votre réponse n'ajoute rien de nouveau à la discussion de cette question.
Sid

-3

Il est très simple de ne rien importer. Ceci est mon code. Cela définira une fonction qui multiplie tous les articles d'une liste et renvoie leur produit.

def myfunc(lst):
    multi=1
    for product in lst:
        multi*=product
    return product

2
Dupliquer à la réponse de DeadChex, la réponse de piSHOCK, la réponse de Shakti Nandan. Ne postez pas de réponse déjà suggérée.
Munim Munna

il devrait également renvoyer plusieurs | - |
Lars
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.