Ajout élément par élément de 2 listes?

244

J'ai maintenant:

list1 = [1, 2, 3]
list2 = [4, 5, 6]

Je souhaite avoir:

[1, 2, 3]
 +  +  +
[4, 5, 6]
|| || ||
[5, 7, 9]

Un simple ajout élémentaire de deux listes.

Je peux sûrement parcourir les deux listes, mais je ne veux pas le faire.

Quelle est la façon la plus Pythonique de le faire?

Sibbs Gambling
la source
Duplication possible du vecteur concis en Python?
Nikos Alexandris

Réponses:

364

Utiliser mapavec operator.add:

>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

ou zipavec une liste de compréhension:

>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]

Comparaisons de synchronisation:

>>> list2 = [4, 5, 6]*10**5
>>> list1 = [1, 2, 3]*10**5
>>> %timeit from operator import add;map(add, list1, list2)
10 loops, best of 3: 44.6 ms per loop
>>> %timeit from itertools import izip; [a + b for a, b in izip(list1, list2)]
10 loops, best of 3: 71 ms per loop
>>> %timeit [a + b for a, b in zip(list1, list2)]
10 loops, best of 3: 112 ms per loop
>>> %timeit from itertools import izip;[sum(x) for x in izip(list1, list2)]
1 loops, best of 3: 139 ms per loop
>>> %timeit [sum(x) for x in zip(list1, list2)]
1 loops, best of 3: 177 ms per loop
Ashwini Chaudhary
la source
10
Si vous utilisez ces énormes tableaux, la solution numpy de @BasSwinckels est probablement quelque chose que vous devriez examiner.
Henry Gomersall du
1
Quelle version de Python avez-vous utilisée pour ces synchronisations?
arshajii
9
NB - en python3, map () renvoie une chose itérable plutôt qu'une liste. Si vous avez besoin d'une liste réelle, la première réponse est une liste (carte (ajouter, liste1, liste2))
FLHerne
Noter le problème de python3 noté par @FLHerne avec mapdeviendra de plus en plus important au fil du temps. Python 2 perdra son support officiel en moins de 3 ans.
nealmcb
1
Il y a de nombreuses fois où la syntaxe python est vraiment élégante et simple, mais malheureusement ce n'est pas l'un d'entre eux. Et pour une tâche aussi simple, c'est dommage .... Pourquoi feraient-ils "+" concaténer les listes alors qu'il y a déjà la méthode .extend ()?
Nic Scozzaro
105

Les autres ont donné des exemples sur la façon de le faire en python pur. Si vous voulez le faire avec des tableaux avec 100 000 éléments, vous devez utiliser numpy:

In [1]: import numpy as np
In [2]: vector1 = np.array([1, 2, 3])
In [3]: vector2 = np.array([4, 5, 6])

Faire l'ajout élément par élément est maintenant aussi trivial que

In [4]: sum_vector = vector1 + vector2
In [5]: print sum_vector
[5 7 9]

comme dans Matlab.

Moment de comparaison avec la version la plus rapide d'Ashwini:

In [16]: from operator import add
In [17]: n = 10**5
In [18]: vector2 = np.tile([4,5,6], n)
In [19]: vector1 = np.tile([1,2,3], n)
In [20]: list1 = [1,2,3]*n
In [21]: list2 = [4,5,6]*n
In [22]: timeit map(add, list1, list2)
10 loops, best of 3: 26.9 ms per loop

In [23]: timeit vector1 + vector2
1000 loops, best of 3: 1.06 ms per loop

C'est donc un facteur 25 plus rapide! Mais utilisez ce qui convient à votre situation. Pour un programme simple, vous ne voulez probablement pas installer numpy, utilisez donc le python standard (et je trouve la version d'Henry la plus Pythonique). Si vous aimez sérieusement le nombre, laissez numpyle gros du travail. Pour les monstres de vitesse: il semble que la solution numpy soit plus rapide au départ n = 8.

Bas Swinckels
la source
59
[a + b for a, b in zip(list1, list2)]
Henry Gomersall
la source
4
@deltab La réponse acceptée est plus rapide ET elle contient cette réponse (plus informative)
Sibbs Gambling
2
@ perfectionm1ng bien que je comprenne votre point (et ne le regrettez pas du tout), je pensais juste qu'il valait la peine de souligner que j'utiliserais toujours la solution que j'ai présentée (qui, étant donné qu'elle ne nécessite aucune importation, est sans doute la plus simple aussi) comme étant sans doute le plus pythonique), ou là où la vitesse compte, la réponse de Bas Swinckel , qui est massivement la bonne option là où la vitesse compte.
Henry Gomersall le
Oui. Merci pour l'avis. Mais c'est essentiellement [sum(x) for x in zip(list1, list2)]la même chose que votre réponse, n'est-ce pas? :)
Sibbs Gambling
4
@ perfectionm1ng Plus ou moins (bien qu'il ait été ajouté après le mien avec une modification :). Personnellement, je préfère la notation a + b avec un déballage explicite pour la lisibilité et la pythonicité.
Henry Gomersall
12

Comme décrit par d'autres, une solution rapide et efficace en termes d'espace utilise numpy (np) avec sa capacité de manipulation vectorielle intégrée:

1. Avec Numpy

x = np.array([1,2,3])
y = np.array([2,3,4])
print x+y

2. Avec intégré

2.1 Lambda

list1=[1, 2, 3]
list2=[4, 5, 6]
print map(lambda x,y:x+y, list1, list2)

Notez que map () prend en charge plusieurs arguments.

2.2 Compréhension zip et liste

list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]
MasterControlProgram
la source
1
+1 pour l'approche lambda. C'est dommage que cette solution soit combinée avec d'autres solutions qui sont dupliquées ailleurs.
LondonRob
10

C'est plus simple à utiliser numpyselon moi:

import numpy as np
list1=[1,2,3]
list2=[4,5,6]
np.add(list1,list2)

Résultats:

Exécution du terminal

Pour des informations détaillées sur les paramètres, consultez ici: numpy.add

Ludwig Zhou
la source
6

Peut-être que "la manière la plus pythonique" devrait inclure la gestion du cas où list1 et list2 ne sont pas de la même taille. L'application de certaines de ces méthodes vous donnera tranquillement une réponse. L'approche numpy vous le fera savoir, très probablement avec une ValueError.

Exemple:

import numpy as np
>>> list1 = [ 1, 2 ]
>>> list2 = [ 1, 2, 3]
>>> list3 = [ 1 ]
>>> [a + b for a, b in zip(list1, list2)]
[2, 4]
>>> [a + b for a, b in zip(list1, list3)]
[2]
>>> a = np.array (list1)
>>> b = np.array (list2)
>>> a+b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2) (3)

Quel résultat souhaiteriez-vous s'il s'agissait d'une fonction de votre problème?

Fred Mitchell
la source
dans ce cas, il faut absolument regarder zip_longestdepuis itertools avec un fillvaluede 0.
Ma0
6

C'est simple avec numpy.add()

import numpy

list1 = numpy.array([1, 2, 3])
list2 = numpy.array([4, 5, 6])
result = numpy.add(list1, list2) # result receive element-wise addition of list1 and list2
print(result)
array([5, 7, 9])

Voir le doc ici

Si vous souhaitez recevoir une liste python:

result.tolist()
Eduardo Basílio
la source
5

Cela fonctionnera pour 2 listes ou plus; itération à travers la liste des listes, mais en utilisant l'addition numpy pour traiter les éléments de chaque liste

import numpy as np
list1=[1, 2, 3]
list2=[4, 5, 6]

lists = [list1, list2]
list_sum = np.zeros(len(list1))
for i in lists:
   list_sum += i
list_sum = list_sum.tolist()    

[5.0, 7.0, 9.0]
litepresence
la source
5

C'est peut-être pythonique et légèrement utile si vous avez un nombre inconnu de listes, et sans rien importer.

Tant que les listes sont de la même longueur, vous pouvez utiliser la fonction ci-dessous.

Ici, le * args accepte un nombre variable d'arguments de liste (mais additionne seulement le même nombre d'éléments dans chacun).

Le * est à nouveau utilisé dans la liste renvoyée pour décompresser les éléments dans chacune des listes.

def sum_lists(*args):
    return list(map(sum, zip(*args)))

a = [1,2,3]
b = [1,2,3]  

sum_lists(a,b)

Production:

[2, 4, 6]

Ou avec 3 listes

sum_lists([5,5,5,5,5], [10,10,10,10,10], [4,4,4,4,4])

Production:

[19, 19, 19, 19, 19]
Aile
la source
3

Utilisez la carte avec la fonction lambda:

>>> map(lambda x, y: x + y, list1, list2)
[5, 7, 9]
Peaters
la source
3

Je ne l'ai pas chronométré mais je pense que ce serait assez rapide:

import numpy as np
list1=[1, 2, 3]
list2=[4, 5, 6]

list_sum = (np.add(list1, list2)).tolist()

[5, 7, 9]
litepresence
la source
3

Si vous devez gérer des listes de tailles différentes, ne vous inquiétez pas! Le merveilleux module itertools vous a couvert:

>>> from itertools import zip_longest
>>> list1 = [1,2,1]
>>> list2 = [2,1,2,3]
>>> [sum(x) for x in zip_longest(list1, list2, fillvalue=0)]
[3, 3, 3, 3]
>>>

En Python 2, zip_longestest appelé izip_longest.

Voir également cette réponse pertinente et commentez une autre question .

jjst
la source
3
[list1[i] + list2[i] for i in range(len(list1))]
wgr
la source
1
Plus pythonique serait[a + b for (a, b) in zip(list1, list2)]
rayryeng
2

Bien que la vraie question ne veuille pas parcourir la liste pour générer le résultat, mais toutes les solutions qui ont été proposées font exactement cela sous le capot!

Pour rafraîchir: Vous ne pouvez pas ajouter deux vecteurs sans regarder tous les éléments vectoriels. Ainsi, la complexité algorithmique de la plupart de ces solutions est Big-O (n). Où n est la dimension du vecteur.

Donc, d'un point de vue algorithmique, l'utilisation d'une boucle for pour générer de manière itérative la liste résultante est également logique et pythonique. Cependant, en outre, cette méthode n'a pas la charge d'appeler ou d'importer une bibliothèque supplémentaire.

# Assumption: The lists are of equal length.
resultList = [list1[i] + list2[i] for i in range(len(list1))]

Les horaires qui sont montrés / discutés ici dépendent du système et de la mise en œuvre, et ne peuvent pas être une mesure fiable pour mesurer l'efficacité de l'opération. Dans tous les cas, la grande complexité O de l'opération d'addition vectorielle est linéaire, c'est-à-dire O (n).

Ehsan
la source
1
a_list = []
b_list = []
for i in range(1,100):
    a_list.append(random.randint(1,100))

for i in range(1,100):
    a_list.append(random.randint(101,200))
[sum(x) for x in zip(a_list , b_list )]
DSBLR
la source