我想组合(zip?)两个python的元组列表,但是匹配一个键。
e.g。我想创建一个带有两个输入列表并生成如下输出的函数:
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
/压缩函数,这将大大简化这一点。
我确定答案已经存在并且显而易见,我只是没有正确的语言来搜索它。
==
((对于它的价值,这是我天真的解决方案。我希望找到更整洁/更pythonic的东西:
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
谢谢))
答案 0 :(得分:11)
>>> [(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)]
答案 1 :(得分:4)
仍然有点混乱,但有效:
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的回答也很好。
答案 2 :(得分:2)
将第二个列表转换为字典,然后您可以检查密钥是否存在而不迭代整个第二个列表:
def func(lst1,lst2):
d2 = dict(lst2)
return [(k,a,d2[k]) for (k,a) in lst1 if d2.has_key(k) ]
答案 3 :(得分:2)
使用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))
这样做的好处是它可以使用任意数量的输入列表,并且对于大型列表具有更好的运行时间。
请注意,这里我把它写成一个生成元组的生成器而不是返回元组列表的函数,但将其转换为列表是微不足道的。