下面的解决方案对于大型列表可能表现更好,但由于排序步骤可能还需要更多内存。
交集可以通过定义的 sortKey 来完成,例如'count' 或字典的哈希将按照https://stackoverflow.com/a/60765557/1497139 的建议使用。该算法对两个列表进行排序并并行迭代,检查两个迭代器的三种可能状态:
- 第一个迭代器落后于第二个迭代器 -> 推进第一个迭代器
- 第二个迭代器落后于第一个迭代器 -> 推进第二个迭代器
- 都在同一个位置 -> 找到了一个交集元素
在给定的示例中,使用“count”字段作为 sortKey 与使用 dict 哈希作为键的结果相同。
[{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}, {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
[{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}, {'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
python 单元测试
def testIntersection(self):
'''
test creating the intersection of a list of dictionaries
'''
list1 = [{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
{'count': 332, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
{'count': 336, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
{'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
{'count': 309, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'}]
list2 = [{'count': 359, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
{'count': 351, 'evt_datetime': datetime.datetime(2015, 10, 23, 8, 45), 'att_value': 'red'},
{'count': 381, 'evt_datetime': datetime.datetime(2015, 10, 22, 8, 45), 'att_value': 'red'}]
listi=ListOfDict.intersect(list1, list2,'count')
print(listi)
self.assertEquals(2,len(listi))
listi=ListOfDict.intersect(list1, list2)
print(listi)
self.assertEquals(2,len(listi))
ListOfDict
'''
Created on 2020-08-11
@author: wf
'''
class ListOfDict(object):
'''
https://stackoverflow.com/questions/33542997/python-intersection-of-2-lists-of-dictionaries/33543164
'''
@staticmethod
def sortKey(d,key=None):
''' get the sort key for the given dict d with the given key
'''
if key is None:
# https://stackoverflow.com/a/60765557/1497139
return hash(tuple(d.items()))
else:
return d[key]
@staticmethod
def intersect(listOfDict1,listOfDict2,key=None):
'''
get the intersection lf the two lists of Dicts by the given key
'''
i1=iter(sorted(listOfDict1, key=lambda k: ListOfDict.sortKey(k, key)))
i2=iter(sorted(listOfDict2, key=lambda k: ListOfDict.sortKey(k, key)))
c1=next(i1)
c2=next(i2)
lr=[]
while True:
try:
val1=ListOfDict.sortKey(c1,key)
val2=ListOfDict.sortKey(c2,key)
if val1<val2:
c1=next(i1)
elif val1>val2:
c2=next(i2)
else:
lr.append(c1)
c1=next(i1)
c2=next(i2)
except StopIteration:
break
return lr