2009-03-12 2 views
20

У меня есть список кортежей (всегда пар), как это:Как суммировать первое значение в каждом кортеже в списке кортежей в Python?

[(0, 1), (2, 3), (5, 7), (2, 1)] 

Я хотел бы найти сумму первых элементов в каждой паре, а именно:

0 + 2 + 5 + 2 

Как я могу сделать это в Python? На данный момент я итерация по списку:

sum = 0 
for pair in list_of_pairs: 
    sum += pair[0] 

У меня есть чувство, что должно быть более Pythonic способом.

+0

Вы ограничены версиями python ниже 2.4? Я спрашиваю, потому что ваш выбранный ответ бесполезно создает временный список. Тривиальный однострочный в python> = 24 является 'sum (p [0] для p в list_of_pairs)'. – juanchopanza

ответ

48

версия совместима с Python 2.3

sum([pair[0] for pair in list_of_pairs]) 

или в последних версиях Python, см this answer или this one.

+2

Я удалил квадратные скобки, потому что они делают это медленнее, поскольку python создает список первым. sum() отлично работает с итераторами. –

+1

gs, вы нарушили код так же, как Дэвид упоминал, что код SilentGhost не работает. Вы превратили понимание списка в выражение генератора (а не итератор), которого не было до Python 2.4. –

+0

Я перевернул редактирование, потому что, если вы собираетесь использовать метод, который несовместим с Python 2.3, это может быть так же, как в ответе SilentGhost. –

33
sum(i for i, j in list_of_pairs) 

сделаю тоже.

+0

Сначала я подумал, но когда я попробовал это в самом быстром Python, я смог получить к нему сообщение, поднял синтаксическую ошибку :-(Оказывается, я тестировал Python 2.3, хотя ... +1 anyway –

+0

+1: предпочитаю это - - Кортежи имеют фиксированный размер, и вы обычно знаете, какой размер. –

+1

Мне тоже нравится этот подход. Но решение Davids также работает с n-кортежами, что может быть предпочтительнее, в зависимости от конкретной проблемы. – 2009-03-12 11:15:12

4

Если у вас очень большой список или генератор, который производит большое количество пар, вы можете использовать подход, основанный на генераторе. Для удовольствия я использую itemgetter() и imap(). Однако простого подхода, основанного на генераторах, может быть достаточно.

import operator 
import itertools 
idx0 = operator.itemgetter(0) 
list_of_pairs = [(0, 1), (2, 3), (5, 7), (2, 1)] 
sum(itertools.imap(idx0, list_of_pairs) 

Редактировать: itertools.imap() доступно в Python 2.3. Таким образом, вы можете использовать подход, основанный на генераторе.

+0

Не намного быстрее, чем два других решения. –

+0

Я не могу прочитать что-то прочитанное о скорости в вопросе. – 2009-03-12 10:59:39

+0

Скорость всегда хорошая, и, по крайней мере, следует упомянуть в ответах. –

3

Obscure (но весело) ответ:

>>> sum(zip(*list_of_pairs)[0]) 
9 

Или когда ZiP являются итерируемых только это должно работать:

>>> sum(zip(*list_of_pairs).__next__()) 
9 
+0

не работает для py3k: объекты zip не подлежат подписке – SilentGhost

+0

.next() должен работать нормально в этом случае –

+0

mmm, 'zip' объект не имеет атрибута 'next'. – SilentGhost

12

Я рекомендую:

sum(i for i, _ in list_of_pairs) 

Примечание:

Использование переменной _ (или __, чтобы избежать confliction с псевдонимом gettext) вместо j имеет по крайней мере два преимущества:

  1. _ (что означает заполнитель) имеет лучшую читаемость
  2. pylint не будет жалоба: «Неиспользованная переменная« j »«
0

Ниже приведен пример кода, вы также можете указать диапазон списка.

def test_lst_sum(): 
    lst = [1, 3, 5] 
    print sum(lst) # 9 
    print sum(lst[1:]) # 8 

    print sum(lst[5:]) # 0 out of range so return 0 
    print sum(lst[5:-1]) # 0 

    print sum(lst[1: -1]) # 3 

    lst_tp = [('33', 1), ('88', 2), ('22', 3), ('44', 4)] 
    print sum(x[1] for x in lst_tp[1:]) # 9 
Смежные вопросы