我有两个词典,如:
dict1 = { (1,2) : 2, (2,3): 3, (1,3): 3}
dict2 = { (1,2) : 1, (1,3): 2}
我想要的输出是两个字典中存在的项目的两个值列表:
[2,3]
[1,2]
我现在正在做的事情是这样的:
list1 = []
list2 = []
for key in dict1.keys():
if key in dict2.keys():
list1.append(dict1.get(key))
list2.append(dict2.get(key))
此代码运行时间太长,这不是我期待的。我想知道是否有更有效的方法可以做到这一点?
答案 0 :(得分:28)
commons = set(dict1).intersection(set(dict2))
list1 = [dict1[k] for k in commons]
list2 = [dict2[k] for k in commons]
答案 1 :(得分:14)
不要使用dict.keys
。在python2.x上,它每次调用时都会创建一个新列表(这是O(N)
操作 - list.__contains__
平均是另一个O(N)
操作。只需依赖字典是可迭代容器的事实(使用O(1)
查找):
list1 = []
list2 = []
for key in dict1:
if key in dict2:
list1.append(dict1.get(key))
list2.append(dict2.get(key))
请注意,在python2.7上,您可以使用viewkeys
直接获取交集:
>>> a = {'foo': 'bar', 'baz': 'qux'}
>>> b = {'foo': 'bar'}
>>> a.viewkeys() & b
set(['foo'])
(在python3.x上,你可以在这里使用keys
而不是viewkeys
)
for key in dict1.viewkeys() & dict2:
list1.append(dict1[key]))
list2.append(dict2[key]))
答案 2 :(得分:4)
您可以在zip()
函数中使用列表推导:
>>> vals1, vals2 = zip(*[(dict1[k], v) for k, v in dict2.items() if k in dict1])
>>>
>>> vals1
(2, 3)
>>> vals2
(1, 2)
或者作为使用视图对象和operator.itemgetter()
的更实用的方法,您可以这样做:
>>> from operator import itemgetter
>>> intersect = dict1.viewkeys() & dict2.viewkeys()
>>> itemgetter(*intersect)(dict1)
(2, 3)
>>> itemgetter(*intersect)(dict2)
(1, 2)
已接受答案的基准:
from timeit import timeit
inp1 = """
commons = set(dict1).intersection(set(dict2))
list1 = [dict1[k] for k in commons]
list2 = [dict2[k] for k in commons]
"""
inp2 = """
zip(*[(dict1[k], v) for k, v in dict2.items() if k in dict1])
"""
inp3 = """
intersect = dict1.viewkeys() & dict2.viewkeys()
itemgetter(*intersect)(dict1)
itemgetter(*intersect)(dict2)
"""
dict1 = {(1, 2): 2, (2, 3): 3, (1, 3): 3}
dict2 = {(1, 2): 1, (1, 3): 2}
print 'inp1 ->', timeit(stmt=inp1,
number=1000000,
setup="dict1 = {}; dict2 = {}".format(dict1, dict2))
print 'inp2 ->', timeit(stmt=inp2,
number=1000000,
setup="dict1 = {}; dict2 = {}".format(dict1, dict2))
print 'inp3 ->', timeit(stmt=inp3,
number=1000000,
setup="dict1 = {}; dict2 = {};from operator import itemgetter".format(dict1, dict2))
输出:
inp1 -> 0.000132083892822
inp2 -> 0.000128984451294
inp3 -> 0.000160932540894
对于长度为10000的字典和随机生成的项目,在100循环中使用:
inp1 -> 1.18336105347
inp2 -> 1.00519990921
inp3 -> 1.52266311646
正如@Davidmh在评论中提到的拒绝为第二种方法引发异常时,您可以将代码包装在try-except
表达式中:
try:
intersect = dict1.viewkeys() & dict2.viewkeys()
vals1 = itemgetter(*intersect)(dict1)
vals2 = itemgetter(*intersect)(dict2)
except TypeError:
vals1 = vals2 = []
答案 3 :(得分:0)
这应该在python3中使用keys
并在python2中使用viewkeys
。这些视图对象的行为类似于集合,并且不需要额外的工作来构建它们......它们只是底层字典键的“视图”。这样就可以保存set
个对象的构造。
common = dict1.viewkeys() & dict2.viewkeys()
list1 = [dict1[k] for k in common]
list2 = [dict2[k] for k in common]
dict_views
个对象可以直接与字典相交,因此以下代码也可以正常工作。我更喜欢上一个样本。
common = dict1.viewkeys() & dict2