Python самый простой способ суммировать пересечение списка списка кортежей

скажем, у меня есть следующие два списка кортежей

myList = [(1, 7), (3, 3), (5, 9)]
otherList = [(2, 4), (3, 5), (5, 2), (7, 8)]

returns => [(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]

Я хотел бы разработать операцию слияния, которая объединяет эти два списка, проверяя любые пересечения на первом элементе кортежа, если есть пересечения, добавьте вторые элементы каждого кортежа в вопросе (объединить два). После операции я хотел бы отсортировать на основе первого элемента.

Я также отправляю это, потому что я думаю, что это довольно распространенная проблема, которая имеет явный решение, но я чувствую, что там может быть очень подходящие для Python решения этого вопроса ;)

4 ответов


используйте словарь для результата:

result = {}
for k, v in my_list + other_list:
    result[k] = result.get(k, 0) + v

Если вам нужен список кортежей, вы можете получить его через result.items(). Результирующий список будет в произвольном порядке, но при желании его можно отсортировать.

(обратите внимание, что я переименовал ваши списки в соответствии с соглашениями стиля Python.)


использовать defaultdict:

from collections import defaultdict
results_dict = defaultdict(int)
results_dict.update(my_list)
for a, b in other_list:
    results_dict[a] += b
results = sorted(results_dict.items())

Примечание: при сортировке последовательностей,sorted сортировка по первому элементу в последовательности. Если первые элементы совпадают, то сравнивается второй элемент. Вы можете дать sorted функция для сортировки, используя key ключевое слово аргумент:

results = sorted(results_dict.items(), key=lambda x: x[1]) #sort by the 2nd item

или

results = sorted(results_dict.items(), key=lambda x: abs(x[0])) #sort by absolute value

метод с использованием itertools:

>>> myList = [(1, 7), (3, 3), (5, 9)]
>>> otherList = [(2, 4), (3, 5), (5, 2), (7, 8)]

>>> import itertools
>>> merged = []
>>> for k, g in itertools.groupby(sorted(myList + otherList), lambda e: e[0]):
...    merged.append((k, sum(e[1] for e in g)))
... 
>>> merged
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]

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


>>> [(k, sum(v for x,v in myList + otherList if k == x)) for k in dict(myList + otherList).keys()]
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
>>>

проверено для обоих Python2.7 и 3.2
dict(myList + otherList).keys() возвращает итерацию, содержащую набор ключей для объединенных списков
sum(...) принимает "k", чтобы снова пройти через Объединенный список и добавить элементы кортежа "v", где k == x

... но дополнительный цикл добавляет накладные расходы на обработку. Используя явный словарь, предложенные Свен Марнах избегает его.