Adição elementar de 2 listas?

244

Eu tenho agora:

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

Eu gostaria de ter:

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

Simplesmente uma adição elemento a elemento de duas listas.

Certamente posso repetir as duas listas, mas não quero fazer isso.

Qual é a maneira mais pitônica de fazer isso?

Sibbs Gambling
fonte
Possível duplicata do vetor Concise adicionando em Python?
Nikos Alexandris

Respostas:

364

Use mapcom operator.add:

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

ou zipcom uma compreensão da lista:

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

Comparações de tempo:

>>> 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
fonte
10
Se você usa essas matrizes enormes, a solução numpy da @BasSwinckels provavelmente é algo que você deve procurar.
precisa saber é o seguinte
1
Qual versão do Python você usou para esses horários?
Arshajii
9
NB - em python3, map () retorna uma coisa iterável ao invés de uma lista. Se você precisa fazer uma lista real, a primeira resposta é list (mapa (add, list1, list2))
FLHerne
Observar o problema python3 observado pelo @FLHerne com se maptornará mais importante ao longo do tempo. O Python 2 perderá o suporte oficial em menos de 3 anos.
nealmcb
1
Existem muitas vezes em que a sintaxe do python é realmente elegante e simples, mas infelizmente esse não é um deles. E para uma tarefa tão simples, é uma pena .... Por que eles "+" concatenariam as listas quando já existe o método .extend ()?
131318 Nic Scozzaro
105

Os outros deram exemplos de como fazer isso em python puro. Se você quiser fazer isso com matrizes com 100.000 elementos, use numpy:

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

Fazer a adição elemento a elemento agora é tão trivial quanto

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

assim como no Matlab.

Tempo para comparar com a versão mais rápida do 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

Portanto, este é um fator 25 mais rápido! Mas use o que se adequa à sua situação. Para um programa simples, você provavelmente não deseja instalar o numpy, então use o python padrão (e acho a versão de Henry a mais Pythonic). Se você estiver em trituração séria de números, numpyfaça o trabalho pesado. Para os loucos por velocidade: parece que a solução numpy é mais rápida n = 8.

Bas Swinckels
fonte
59
[a + b for a, b in zip(list1, list2)]
Henry Gomersall
fonte
4
@deltab a resposta aceita é mais rápido e contém esta resposta (mais informativo)
Sibbs Gambling
2
@ perfectionm1ng embora eu entenda seu ponto de vista (e não o inveje nem um pouco), apenas achei que vale a pena salientar que eu sempre usaria a solução que apresentei (que, dado que não requer importações, é sem dúvida a mais simples) indiscutivelmente a mais pitônica), ou onde a velocidade conta, a resposta de Bas Swinckel , que é esmagadoramente a opção certa para a velocidade.
Henry Gomersall
Sim. Obrigado pela opinião. Mas essencialmente [sum(x) for x in zip(list1, list2)]é o mesmo que sua resposta, não é? :)
Sibbs Gambling
4
@ perfectionm1ng Mais ou menos (embora tenha sido adicionado após o meu com uma edição :). Pessoalmente, prefiro a notação a + b com desempacotamento explícito de tuplas para facilitar a leitura e a pitonicidade.
Henry Gomersall
12

Conforme descrito por outros, uma solução rápida e também eficiente em termos de espaço está usando o numpy (np) com sua capacidade de manipulação de vetores integrada:

1. Com Numpy

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

2. Com embutidos

2.1 Lambda

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

Observe que map () suporta vários argumentos.

2.2 compreensão de zip e lista

list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]
MasterControlProgram
fonte
1
+1 para a abordagem lambda. É uma pena que esta solução seja combinada com outras soluções duplicadas em outros lugares.
usar o seguinte código
10

É mais simples de usar numpyda minha opinião:

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

Resultados:

Execução do terminal

Para informações detalhadas sobre parâmetros, verifique aqui: numpy.add

Ludwig Zhou
fonte
6

Talvez "a maneira mais pitônica" deva incluir lidar com o caso em que list1 e list2 não sejam do mesmo tamanho. A aplicação de alguns desses métodos dará uma resposta silenciosa. A abordagem numpy permitirá que você saiba, provavelmente com um ValueError.

Exemplo:

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)

Qual resultado você pode querer se isso estiver relacionado a uma função no seu problema?

Fred Mitchell
fonte
neste caso, deve-se definitivamente procurar em zip_longestitertools com um fillvaluede 0.
Ma0
6

Isso é simples com 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])

Veja o documento aqui

Se você deseja receber uma lista python:

result.tolist()
Eduardo Basílio
fonte
5

Isso funcionará para 2 ou mais listas; iterando pela lista de listas, mas usando adição numpy para lidar com 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]
presença
fonte
5

Talvez isso seja python e um pouco útil se você tiver um número desconhecido de listas e sem importar nada.

Desde que as listas tenham o mesmo comprimento, você pode usar a função abaixo.

Aqui, o * args aceita um número variável de argumentos da lista (mas apenas soma o mesmo número de elementos em cada um).

O * é usado novamente na lista retornada para descompactar os elementos em cada uma das listas.

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

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

sum_lists(a,b)

Resultado:

[2, 4, 6]

Ou com 3 listas

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

Resultado:

[19, 19, 19, 19, 19]
Asa
fonte
3

Use o mapa com a função lambda:

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

Eu não cronometrei, mas suspeito que isso seria bem rápido:

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

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

[5, 7, 9]
presença
fonte
3

Se você precisar lidar com listas de tamanhos diferentes, não se preocupe! O maravilhoso módulo de ferramentas tem você coberto:

>>> 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]
>>>

No Python 2, zip_longesté chamado izip_longest.

Veja também esta resposta relevante e comente outra pergunta .

jjst
fonte
3
[list1[i] + list2[i] for i in range(len(list1))]
wgr
fonte
1
Mais pythonic seria[a + b for (a, b) in zip(list1, list2)]
rayryeng
2

Embora a questão real não queira percorrer a lista para gerar o resultado, mas todas as soluções propostas fazem exatamente isso por baixo do capô!

Para atualizar: Você não pode adicionar dois vetores sem examinar todos os elementos do vetor. Portanto, a complexidade algorítmica da maioria dessas soluções é Big-O (n). Onde n é a dimensão do vetor.

Portanto, do ponto de vista algorítmico, o uso de um loop for para gerar iterativamente a lista resultante também é lógico e pitônico. No entanto, além disso, esse método não tem a sobrecarga de chamar ou importar nenhuma biblioteca adicional.

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

Os horários que estão sendo mostrados / discutidos aqui são dependentes do sistema e da implementação e não podem ser medidas confiáveis ​​para medir a eficiência da operação. De qualquer forma, a grande complexidade de O da operação de adição de vetores é linear, significando O (n).

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