Python zip по ключу
Я хотел бы объединить (zip?) два списка кортежей python, но совпадающих по ключу.
Например, я хотел бы создать функцию, которая принимает два входных списка и выдает такой вывод:
lst1 = [(0, 1.1), (1, 1.2), (2, 1.3), (5, 2.5)]
lst2 = [ (1, 4.5), (2, 3.4), (4, 2.3), (5, 3.2)]
desiredOutput = [(1, 1.2, 4.5), (2, 1.3, 3.4), (5, 2.5, 3.2)]
Я мог бы сделать это очень беспорядочно и вручную с петлями, но я полагаю, что должны быть некоторые функции itertools / zipping, которые значительно упростят это.
Я уверен, что ответ существует и очевиден, просто у меня нет подходящей терминологии для его поиска.
==
(( Как бы то ни было, вот мое наивное решение. Я надеялся найти что-то аккуратнее / более подходящие для Python:
def key_zipper(lst1, lst2):
dict1 = dict(lst1)
dict2 = dict(lst2)
intersectKeys = [k for k in dict1.keys() if k in dict2.keys()]
output = []
for key in intersectKeys:
output.append((key, dict1[key], dict2[key]))
return output
Спасибо ))
4 ответов:
>>> [(i, a, b) for i, a in lst1 for j, b in lst2 if i==j] [(1, 1.2, 4.5), (2, 1.3, 3.4), (5, 2.5, 3.2)]
Все еще немного грязно, но работает:
def combine(lst1, lst2): d2 = dict(lst2) return [(k, v, d2[k]) for (k, v) in lst1 if k in d2]Обновление :
Если бы я действительно использовал это в производственном коде, я бы немного рефакторировал:
def dict_intersection(d1, d2): return [(k,v,d2[k]) for (k,v) in d1.items() if k in d2]И тогда в вашем случае я бы позвонил
lst1 = [(0, 1.1), (1, 1.2), (2, 1.3), (5, 2.5)] lst2 = [(1, 4.5), (2, 3.4), (4, 2.3), (5, 3.2)] common = dict_intersection(dict(lst1), dict(lst2))Ответ@Vincent-тоже хороший вариант.
Преобразуйте второй список в словарь, после чего вы можете проверить, присутствует ли ключ, не повторяя весь второй список:
def func(lst1,lst2): d2 = dict(lst2) return [(k,a,d2[k]) for (k,a) in lst1 if d2.has_key(k) ]
Решение с использованием
itertools.groupbyи ещеheapq.merge:from itertools import groupby from heapq import merge from operator import itemgetter def key_zipper(*lst): for k, v in groupby(merge(*lst), itemgetter(0)): yield (k,) + tuple(map(itemgetter(1), v)) lst1 = [(0, 1.1), (1, 1.2), (2, 1.3), (5, 2.5)] lst2 = [ (1, 4.5), (2, 3.4), (4, 2.3), (5, 3.2)] print(list(key_zipper(lst1, lst2))) # [(0, 1.1), (1, 1.2, 4.5), (2, 1.3, 3.4), (4, 2.3), (5, 2.5, 3.2)]
mergeиgroupbyоба нуждаются в сортировке входных данных. Если вы не всегда сортируете список, то вам нужно обязательно сделать это:def key_zipper(*lst): for k, v in groupby(merge(*map(sorted, lst)), itemgetter(0)): yield (k,) + tuple(map(itemgetter(1), v))Это имеет то преимущество, что он работает с произвольным количеством входных списков, и имеет лучшее время выполнения для больших списков.
Обратите внимание, что здесь я написал его как генератор, выдающий кортежи, а не функцию, возвращающую список кортежей, но преобразующую его в список тривиален.
Comments