Поэлементное добавление 2 списков?


244

Теперь у меня есть:

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

Я хочу иметь:

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

Просто поэлементное добавление двух списков.

Я, конечно, могу повторить два списка, но я не хочу этого делать.

Какой самый питонский способ сделать это?


Ответы:


364

Используйте mapс operator.add:

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

или zipс пониманием списка:

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

Сроки сравнения:

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

10
Если вы используете эти огромные массивы, то, вероятно, вам стоит взглянуть на решение nBupy @BasSwinckels.
Генри Гомерсалл

1
Какую версию Python вы использовали для этих времен?
Аршаджи

9
Примечание: в python3 map () возвращает итеративную вещь, а не список. Если вам нужен фактический список, первым ответом будет список (карта (добавить,
список1, список2

Принимая во внимание, что проблема с python3, отмеченная @FLHerne, со временем mapстанет более важной. Python 2 потеряет официальную поддержку менее чем за 3 года.
nealmcb

1
Во многих случаях синтаксис Python действительно элегантен и прост, но, к сожалению, это не один из них. И для такой простой задачи очень жаль ... Зачем им "+" объединять списки, когда уже есть метод .extend ()?
Ник Скосзаро

105

Другие привели примеры, как это сделать на чистом питоне. Если вы хотите сделать это с массивами с 100.000 элементов, вы должны использовать numpy:

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

Делать поэлементное добавление теперь так же тривиально, как

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

как в Matlab.

Сроки, чтобы сравнить с самой быстрой версией 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

Так что это в 25 раз быстрее! Но используйте то, что подходит вашей ситуации. Для простой программы вы, вероятно, не хотите устанавливать numpy, поэтому используйте стандартный python (и я считаю версию Henry самой Pythonic). Если у вас серьезные проблемы с числом, позвольте numpyсделать тяжелую работу. Для скоростных фанатов: кажется, что решение ошкуриться быстрее, начиная с n = 8.


59
[a + b for a, b in zip(list1, list2)]

4
@deltab Принятый ответ быстрее, и он содержит этот ответ (более информативный)
Sibbs Gambling

2
@ perfectionm1ng, хотя я понимаю вашу точку зрения (и не жалею об этом ни на шаг), я просто подумал, что стоит указать, что я всегда буду использовать любое из представленных мной решений (которое, учитывая, что оно не требует импорта, является, пожалуй, самым простым, также как, возможно, более питонический), или, где скорость имеет значение, ответ Баса Суинкеля , который в подавляющем большинстве является правильным вариантом, где скорость имеет значение.
Генри Гомерсалл,

Да. Спасибо за мнение. Но по сути [sum(x) for x in zip(list1, list2)]это то же самое, что и ваш ответ, не так ли? :)
Sibbs Gambling

4
@ perfectionm1ng Более или менее (хотя он был добавлен после моего редактирования). Лично я предпочитаю нотацию a + b с явной распаковкой кортежей для удобства чтения и pythonicness.
Генри Гомерсалл,

12

Как описано другими, в быстром и экономически эффективном решении используется numpy (np) со встроенной возможностью манипулирования вектором:

1. С Numpy

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

2. Со встроенными модулями

2.1 Лямбда

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

Обратите внимание, что map () поддерживает несколько аргументов.

2.2 zip и понимание списка

list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]

1
+1 за лямбда-подход. Обидно, что это решение сочетается с другими решениями, которые дублируются в других местах.
LondonRob

10

На numpyмой взгляд , проще в использовании :

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

Полученные результаты:

Терминальное исполнение

Для получения подробной информации о параметрах, проверьте здесь: numpy.add


6

Возможно, «самый питонический способ» должен включать обработку случая, когда list1 и list2 имеют разный размер. Применение некоторых из этих методов тихо даст вам ответ. Обдуманный подход даст вам знать, скорее всего, с помощью ValueError.

Пример:

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)

Какой результат вы могли бы получить, если бы это было функцией вашей проблемы?


в этом случае определенно стоит посмотреть zip_longestиз itertools с помощью fillvalueof 0.
Ma0


5

Это будет работать для 2 или более списков; перебирая список списков, но используя добавление numpy для работы с элементами каждого списка

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]

5

Возможно, это питон и немного полезен, если у вас есть неизвестное количество списков, и ничего не импортировать.

Пока списки имеют одинаковую длину, вы можете использовать функцию ниже.

Здесь * args принимает переменное число аргументов списка (но только суммирует одинаковое количество элементов в каждом).

* Снова используется в возвращаемом списке для распаковки элементов в каждом из списков.

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

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

sum_lists(a,b)

Вывод:

[2, 4, 6]

Или с 3 списками

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

Вывод:

[19, 19, 19, 19, 19]

3

Используйте карту с лямбда-функцией:

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

3

Я не рассчитал это, но подозреваю, что это будет довольно быстро:

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

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

[5, 7, 9]

3

Если вам нужно обрабатывать списки разных размеров, не беспокойтесь! Замечательный модуль itertools содержит информацию о вас:

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

В Python 2 zip_longestэто называется izip_longest.

Смотрите также этот соответствующий ответ и комментируйте другой вопрос .


3
[list1[i] + list2[i] for i in range(len(list1))]

1
Более питонным будет[a + b for (a, b) in zip(list1, list2)]
Rayryeng

2

Хотя реальный вопрос не хочет перебирать список для получения результата, но все предложенные решения делают именно это под капотом!

Чтобы обновить: Вы не можете добавить два вектора, не просматривая все элементы вектора. Итак, алгоритмическая сложность большинства этих решений - Big-O (n). Где n - размерность вектора.

Таким образом, с алгоритмической точки зрения использование цикла for для итеративной генерации результирующего списка также логично и питонно. Однако, кроме того, у этого метода нет накладных расходов на вызов или импорт какой-либо дополнительной библиотеки.

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

Времена, которые показаны / обсуждаются здесь, зависят от системы и реализации и не могут быть надежной мерой для измерения эффективности операции. В любом случае, большая сложность O операции сложения векторов линейна, что означает O (n).


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 )]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.