Слияние / добавление списков в Python - PullRequest
34 голосов
/ 05 ноября 2008

Я почти уверен, что должен быть более Pythonic способ сделать это - но я не могу думать об одном: как я могу объединить двумерный список в одномерный список? Вроде как zip / map, но с более чем двумя итераторами.

Пример - у меня есть следующий список:

array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Я хочу иметь

result = [12, 15, 18] # [1+4+7, 2+5+8, 3+6+9]

Пока что я придумал:

def add_list(array):
    number_items = len(array[0])
    result = [0] * number_items
    for index in range(number_items):
        for line in array:
            result[index] += line[index]
    return result

Но это выглядит не очень элегантно / Pythonic для меня. Помимо не проверки, все ли «строки» в 2D-массиве имеют одинаковую длину, могут ли они быть добавлены друг к другу и т. Д. Что может быть лучше для этого?

Ответы [ 8 ]

70 голосов
/ 05 ноября 2008
[sum(a) for a in zip(*array)]
63 голосов
/ 05 ноября 2008

[сумма (значение) для значения в zip (* массив)] довольно стандартна.

Это может помочь вам понять это:

In [1]: array=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [2]: array
Out[2]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [3]: *array
------------------------------------------------------------
   File "<ipython console>", line 1
     *array
     ^
<type 'exceptions.SyntaxError'>: invalid syntax

Унарная звезда сама по себе не является оператором. Развертывает элементы массива в аргументы в вызовах функций.

In [4]: zip(*array)
Out[4]: [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

zip () - встроенная функция

In [5]: zip(*array)[0]
Out[5]: (1, 4, 7)

каждый элемент списка, возвращаемого zip, представляет собой набор нужных вам чисел.

In [6]: sum(zip(*array)[0])
Out[6]: 12

In [7]: [sum(values) for values in zip(*array)]
Out[7]: [12, 15, 18]
14 голосов
/ 05 ноября 2008

Альтернативный способ:

map(sum, zip(*array))
8 голосов
/ 05 ноября 2008

Если вы делаете много такого рода вещей, вы хотите узнать о scipy.

>>> import scipy
>>> sum(scipy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
array([12, 15, 18])

Все размеры массивов проверяются автоматически. Сумма производится в чистом C, так что это очень быстро. scipy массивы также очень эффективно используют память.

Недостатком является то, что вы зависите от довольно сложного стороннего модуля. Но это очень хороший компромисс для многих целей.

3 голосов
/ 25 февраля 2011

Согласитесь с пятью колокольчиками, но вы также можете использовать Numpy, который представляет собой меньшую (более быстрый импорт) и более общую реализацию массивоподобных вещей. (на самом деле, это зависимость scipy). Это отличные инструменты, которые, как уже было сказано, «необходимо использовать», если вы имеете дело с такого рода манипуляциями.

2 голосов
/ 06 ноября 2012

Поздно к игре, и это не такой хороший ответ, как некоторые другие, но я подумал, что это довольно мило:

map(lambda *x:sum(x),*array)

Жаль, что sum(1,2,3) не работает. Если бы это произошло, мы могли бы устранить глупую lambda там, но я полагаю, что это затруднило бы определить, какой (если таковой имеется) из элементов является «началом» суммы. Вы должны были бы изменить это на аргумент только с ключевым словом, который сломал бы много сценариев ... О, хорошо. Я думаю, мы просто будем жить с lambda.

0 голосов
/ 04 апреля 2015

Вы можете просто сделать это:

print [sum(x) for x in zip(*array)]

Если вы хотите перебирать списки таким способом, вы можете использовать chain модуля itertools:

from itertools import chain

for x in array.chain.from_iterable(zip(*array)):
    print x   
# prints 1, 4, 7, 2, 5, 8, ...
0 голосов
/ 03 апреля 2015

[сумма (a) для z in (* массив)]

Мне это нравится. Мне нужно было что-то связанное для чередования объектов в списке элементов, придумало нечто похожее, но более сжатое для списков четной длины:

sum(zip(*array),())

например, чередование двух списков:

a = [1,2,3]
b = ['a','b','c']
sum(zip(a,b),())
(1, 'a', 2, 'b', 3, 'c')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...