Елементно додавання 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
Якщо ви використовуєте ці величезні масиви, то, можливо, ви повинні дивитись нумероване рішення від @BasSwinckels.
Генрі Гомерсалл

1
Яку версію Python ви використовували для цих таймінгів?
Аршаджі

9
Примітка - у python3 map () повертає ітерабельну річ, а не список. Якщо вам потрібен фактичний список, перша відповідь - це список (карта (додати, список1, список2))
FLHerne

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

1
Багато разів синтаксис пітона є елегантним та простим, але, на жаль, це не один із них. І для такого простого завдання шкода .... Чому вони змушують "+" об'єднувати списки, коли вже існує метод .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.

Час порівняння з найшвидшою версією Ашвіні:

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 (і я вважаю версію Генрі найбільш пітонічною). Якщо ви стикаєтеся з серйозним скороченням кількості, нехай 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)]це те саме, що і ваша відповідь, чи не так? :)
Сіббс Азартні ігри

4
@ perfectionm1ng Більш-менш (хоча вона була додана після моєї редакції :). Особисто я віддаю перевагу позначення a + b з явним розпакуванням кортежу для читабельності та пітонічності.
Генрі Гомерсалл

12

Як описано іншими, швидке, а також ефективне для простору рішення використовує numpy (np) із вбудованою функцією векторного маніпулювання:

1. З нумізкою

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 розуміння поштових записів та списку

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 не мають однакового розміру. Застосування деяких із цих методів спокійно дасть вам відповідь. Підхід numpet повідомить вас, швидше за все, про 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 з fillvalueз 0.
Ма0

6

З цим просто 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])

Дивіться док. Тут

Якщо ви бажаєте отримати список пітона:

result.tolist()

5

Це буде працювати для 2 або більше списків; ітерація за допомогою списку списків, але з використанням нумерованого додавання для обробки елементів кожного списку

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

Якщо вам потрібно обробляти списки різних розмірів, не хвилюйтеся! Чудовий модуль 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 - розмірність вектора.

Отже, з алгоритмічної точки зору, використання циклу для ітераційного генерування отриманого списку є логічним і пітонічним. Однак, крім того, цей метод не має накладних витрат на виклик чи імпорт будь-якої додаткової бібліотеки.

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

Терміни, які тут демонструються / обговорюються, залежать від системи та впровадження, і не можуть бути надійним показником для вимірювання ефективності операції. У будь-якому випадку велика складність О операції додавання вектора є лінійною, тобто 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.