比较Python中的多个词典

时间:2008-11-24 16:02:37

标签: python data-mining

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

当用户从列表控件中选择多个条目(按下CTRL或单击时移位)时,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'。

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

我有一个模糊的想法,列表推导将是要走的路,但我只知道如何将两个列表与列表推导进行比较,而不是n列表。任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:7)

>>> 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')])

首先,我创建了一个生成器,它将dicts列表转换为一组可重复的键值对。你可以在这里使用列表理解,但是这种方式不会将你的整个列表转换成另一个列表,如果你不知道它有多大,那就很有用。

然后我使用reduce来应用一个函数来找到每个集合之间的公共值。它找到了集合1和1的交集。设置2,它本身就是一个集合,然后是该集合的交集。设置3等myset生成器将根据需要快速地将每个集合提供给reduce函数,直到完成。

我认为reduce已被弃用为Python 3.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可以接受键,值对的任何迭代器,例如最后返回的元组集。

答案 1 :(得分:7)

我的回答与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。在我看来,这更具可读性,因为这直观地读作“减少使用集合交集运算符减少此列表”。这也应该快得多,因为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']

答案 2 :(得分:2)

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

def IntersectDicts( d1, d2 ) :
    return dict(filter(lambda (k,v) : k in d2 and d2[k] == v, d1.items()))

然后我们可以用它来处理任意数量的词典:

result = reduce(IntersectDicts, MyList)

答案 3 :(得分:1)

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

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'}

答案 4 :(得分:0)

对不起,是的,'输入':'购买'也是常见值之一。应该已登录编辑问题。