Elemento de sabia adición de 2 listas?

244

Ahora tengo:

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

Deseo tener:

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

Simplemente una adición por elementos de dos listas.

Seguramente puedo repetir las dos listas, pero no quiero hacer eso.

¿Cuál es la forma más pitónica de hacerlo?

Sibbs Gambling
fuente
Posible duplicado del vector conciso que se agrega en Python?
Nikos Alexandris el

Respuestas:

364

Usar mapcon operator.add:

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

o zipcon una lista de comprensión:

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

Comparaciones de tiempo:

>>> 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
fuente
10
Si usa esas enormes matrices, la solución complicada de @BasSwinckels es probablemente algo que debería estar mirando.
Henry Gomersall
1
¿Qué versión de Python usaste para esos tiempos?
arshajii
99
NB: en python3, map () devuelve una cosa iterable en lugar de una lista. Si necesita una lista real, la primera respuesta es list (map (add, list1, list2))
FLHerne
Observar el problema de python3 señalado por @FLHerne con mapsolo se volverá más importante con el tiempo. Python 2 perderá el soporte oficial en menos de 3 años.
nealmcb
1
Muchas veces la sintaxis de Python es realmente elegante y simple, pero desafortunadamente esta no es una de ellas. Y para una tarea tan simple, es una pena ... ¿Por qué harían que "+" concatene las listas cuando ya existe el método .extend ()?
Nic Scozzaro
105

Los otros dieron ejemplos de cómo hacer esto en Python puro. Si desea hacer esto con matrices con 100.000 elementos, debe usar numpy:

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

Hacer la suma por elementos es ahora tan trivial como

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

como en Matlab

Momento para comparar con la versión más rápida de 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

¡Entonces este es un factor 25 más rápido! Pero usa lo que se adapte a tu situación. Para un programa simple, probablemente no quieras instalar numpy, así que usa Python estándar (y creo que la versión de Henry es la más Pythonic). Si te gustan los números serios, deja numpyel trabajo pesado. Para los fanáticos de la velocidad: parece que la solución numpy es más rápida al comenzar n = 8.

Bas Swinckels
fuente
59
[a + b for a, b in zip(list1, list2)]
Henry Gomersall
fuente
44
@deltab La respuesta aceptada es más rápida Y contiene esta respuesta (más informativa)
Sibbs Gambling
2
@ perfectionm1ng, aunque entiendo tu punto de vista (y no lo disguste ni un poco), solo pensé que valía la pena señalar que siempre usaría la solución que he presentado (lo que dado que no requiere importaciones es posiblemente también la más simple) como podría decirse que es el más pitónico), o donde la velocidad cuenta, la respuesta de Bas Swinckel , que es abrumadoramente la opción correcta donde la velocidad importa.
Henry Gomersall el
Si. Gracias por la opinion. Pero esencialmente [sum(x) for x in zip(list1, list2)]es lo mismo que tu respuesta, ¿no? :)
Sibbs Gambling
44
@ perfectionm1ng Más o menos (aunque se agregó después del mío con una edición :). Personalmente, prefiero la notación a + b con desempaquetado explícito de tuplas para facilitar la lectura y la pitonicidad.
Henry Gomersall
12

Según lo descrito por otros, una solución rápida y eficiente en el espacio está usando numpy (np) con su capacidad incorporada de manipulación de vectores:

1. Con Numpy

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

2. Con incorporados

2.1 Lambda

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

Tenga en cuenta que map () admite múltiples argumentos.

2.2 comprensión de zip y lista

list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]
MasterControlProgram
fuente
1
+1 para el enfoque lambda. Es una pena que esta solución se combine con otras soluciones que se duplican en otros lugares.
LondonRob
10

Es más simple de usar numpydesde mi opinión:

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

Resultados:

Ejecución terminal

Para obtener información detallada sobre los parámetros, consulte aquí: numpy.add

Ludwig Zhou
fuente
6

Quizás "la forma más pitónica" debería incluir el manejo del caso donde list1 y list2 no son del mismo tamaño. La aplicación de algunos de estos métodos le dará una respuesta en silencio. El enfoque numpy te lo hará saber, muy probablemente con un ValueError.

Ejemplo:

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)

¿Qué resultado podría desear si esto estuviera en una función de su problema?

Fred Mitchell
fuente
en este caso, uno definitivamente debería mirar zip_longestdesde itertools con un fillvaluede 0.
Ma0 hace
6

Esto es simple con 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])

Ver documento aquí

Si desea recibir una lista de Python:

result.tolist()
Eduardo Basílio
fuente
5

Esto funcionará para 2 o más listas; iterando a través de la lista de listas, pero usando la suma numpy para tratar con elementos de cada lista

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]
presencia lite
fuente
5

Quizás esto sea pitónico y ligeramente útil si tiene un número desconocido de listas y sin importar nada.

Mientras las listas sean de la misma longitud, puede usar la siguiente función.

Aquí el * args acepta un número variable de argumentos de lista (pero solo suma el mismo número de elementos en cada uno).

El * se usa nuevamente en la lista devuelta para descomprimir los elementos en cada una de las listas.

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

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

sum_lists(a,b)

Salida:

[2, 4, 6]

O con 3 listas

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

Salida:

[19, 19, 19, 19, 19]
Ala
fuente
3

Use el mapa con la función lambda:

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

No lo he cronometrado, pero sospecho que esto sería bastante rápido:

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

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

[5, 7, 9]
presencia lite
fuente
3
[list1[i] + list2[i] for i in range(len(list1))]
wgr
fuente
1
Más pitónico sería[a + b for (a, b) in zip(list1, list2)]
rayryeng
2

Aunque, la pregunta real no quiere iterar sobre la lista para generar el resultado, ¡pero todas las soluciones que se han propuesto hacen exactamente eso debajo del capó!

Para actualizar: No puede agregar dos vectores sin examinar todos los elementos del vector. Entonces, la complejidad algorítmica de la mayoría de estas soluciones son Big-O (n). Donde n es la dimensión del vector.

Entonces, desde un punto de vista algorítmico, usar un bucle for para generar iterativamente la lista resultante también es lógico y pitónico. Sin embargo, además, este método no tiene la sobrecarga de llamar o importar ninguna biblioteca adicional.

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

Los tiempos que se muestran / discuten aquí dependen del sistema y la implementación, y no pueden ser medidas confiables para medir la eficiencia de la operación. En cualquier caso, la gran complejidad de O de la operación de suma de vectores es lineal, lo que significa O (n).

Ehsan
fuente
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
fuente