比较Python中的多个词典

比较Python中的多个词典,python,data-mining,Python,Data Mining,我是Python新手,现在遇到了一个无法通过谷歌搜索解决的问题。我已经使用wxPython和ObjectiveListView构建了一个GUI。在它的中心,GUI有一个列表控件,以X行(数据由用户加载)和五列显示数据 当用户从列表控件中选择多个条目时(单击时按CTRL或shift),ObjectiveListView模块会给我一个字典列表,这些字典包含列表控件行中的数据。这正是我想要的,很好 返回的列表如下所示: print MyList [{'id':1023, 'type':'Purchas

我是Python新手,现在遇到了一个无法通过谷歌搜索解决的问题。我已经使用wxPython和ObjectiveListView构建了一个GUI。在它的中心,GUI有一个列表控件,以X行(数据由用户加载)和五列显示数据

当用户从列表控件中选择多个条目时(单击时按CTRL或shift),ObjectiveListView模块会给我一个字典列表,这些字典包含列表控件行中的数据。这正是我想要的,很好

返回的列表如下所示:

print MyList
[{'id':1023, 'type':'Purchase', 'date':'23.8.2008', 'sum':'-21,90', 'target':'Apple Store'}, {'id':1024, 'type':'Purchase', 'date':'24.8.2008', 'sum':'-21,90', 'target':'Apple Store'}, {'id':23, 'type':'Purchase', 'date':'2.8.2008', 'sum':'-21,90', 'target':'Apple Store'}]
所有字典都有相同的键,但值会发生变化。“id”值是唯一的。问题从这里开始。我想获得用户选择的所有项目的通用值。在上面的列表中,它们是'sum':'21,90'和'target':'Apple Store'

我不知道如何正确地比较清单上的词条。一个大问题是,我事先不知道列表中包含多少dict,因为它是由用户决定的


我有一个模糊的想法,列表理解将是一种方式,但我只知道如何比较两个列表与列表理解,而不是n个列表。任何帮助都将不胜感激。

抱歉,是的,'type':'Purchase'也是常见值之一。应该登录以编辑问题

>>> mysets = (set(x.items()) for x in MyList)
>>> reduce(lambda a,b: a.intersection(b), mysets)
set([('sum', '-21,90'), ('type', 'Purchase'), ('target', 'Apple Store')])
首先,我创建了一个生成器,它将dict列表转换为一组可编辑的键、值对序列。您可以在这里使用列表理解,但这种方式不会将您的整个列表转换为另一个列表,如果您不知道它会有多大,这将非常有用

然后我使用reduce应用了一个函数,该函数可以找到每个集合之间的公共值。它找到集合1和集合2的交集,这本身就是一个集合,然后找到集合3和集合3的交集,等等。mysets生成器将根据需要将每个集合提供给reduce函数,直到完成为止

我相信reduce作为python3.0中的内置工具已经被弃用,但应该仍然可以在functools中使用

当然,您可以通过使用生成器表达式替换reduce中的myset使其成为一行,但这会降低IMO的可读性。实际上,我甚至可能更进一步,将lambda分解为自己的行:

>>> mysets = (set(x.items()) for x in MyList)
>>> find_common = lambda a,b: a.intersection(b)
>>> reduce(find_common, mysets)
set([('sum', '-21,90'), ('type', 'Purchase'), ('target', 'Apple Store')])
如果您需要最终结果是一个dict,只需像这样包装它:

>>> dict(reduce(find_common, mysets))
{'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'}

dict可以接受键、值对的任何迭代器,例如末尾返回的元组集。

首先,我们需要一个函数来计算两个字典的交集:

def IntersectDicts( d1, d2 ) :
    return dict(filter(lambda (k,v) : k in d2 and d2[k] == v, d1.items()))
result = reduce(IntersectDicts, MyList)
common = {}
for k in MyList[0]:
    for i in xrange(1,len(MyList)):
        if MyList[0][k] != MyList[i][k]: continue
        common[k] = MyList[0][k]

>>> common
{'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'}
然后,我们可以使用它处理任意数量的词典:

def IntersectDicts( d1, d2 ) :
    return dict(filter(lambda (k,v) : k in d2 and d2[k] == v, d1.items()))
result = reduce(IntersectDicts, MyList)
common = {}
for k in MyList[0]:
    for i in xrange(1,len(MyList)):
        if MyList[0][k] != MyList[i][k]: continue
        common[k] = MyList[0][k]

>>> common
{'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'}

我的答案与Matthew Trevor的答案相同,只是有一点不同:

>>> mysets = (set(x.items()) for x in MyList)
>>> reduce(set.intersection, mysets)
set([('sum', '-21,90'), ('type', 'Purchase'), ('target', 'Apple Store')])
这里我使用
set.intersection
而不是创建一个新的lambda。在我看来,这更具可读性,因为它直观地读作“reduce是使用set intersection操作符减少此列表”。这也应该快得多,因为
set.intersection
是一个内置的C函数

要完全回答您的问题,您可以使用列表提取值:

>>> mysets = (set(x.items()) for x in MyList)
>>> result = reduce(set.intersection, mysets)
>>> values = [r[1] for r in result]
>>> values
['-21,90', 'Purchase', 'Apple Store']
这对我来说是一条线。但这完全取决于你:

>>> [r[1] for r in reduce(set.intersection, (set(x.items()) for x in myList))]
['-21,90', 'Purchase', 'Apple Store']

由于您只查找公共集,因此可以将第一个字典中的键与所有其他字典中的键进行比较:

def IntersectDicts( d1, d2 ) :
    return dict(filter(lambda (k,v) : k in d2 and d2[k] == v, d1.items()))
result = reduce(IntersectDicts, MyList)
common = {}
for k in MyList[0]:
    for i in xrange(1,len(MyList)):
        if MyList[0][k] != MyList[i][k]: continue
        common[k] = MyList[0][k]

>>> common
{'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'}

“类型”:“购买”不也是一种常见的价值观吗?你对“常见价值观”的定义是什么?您的意思是希望在排除其他键值的同时获得某些键值的结果吗?或者,检索多次出现的值的结果?这可能有点夸张,但值得知道set.intersection将使用任何序列类型作为参数,因此您可以将整个过程简化为:
reduce(lambda a,b:a.intersection(b.items()),MyList[1:],set(MyList[0].items())
请添加一条警告,说明键和值应可散列。通常是这样,但让我们尽量减少意外的可能性。对于3000个项目的列表,您的版本比我的版本快5-600个usecs,因此几乎没有“快得多”: