4

我是 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'。

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

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

4

5 回答 5

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

首先,我创建了一个生成器,它将字典列表转换为可迭代的键值对集合序列。您可以在此处使用列表推导,但这种方式不会将您的整个列表转换为另一个列表,如果您不知道它有多大,这很有用。

然后我使用reduce 来应用一个函数来查找每组之间的共同值。它找到集合 1 和集合 2 的交集,它本身就是一个集合,然后是那个集合和集合 3 的交集,等等。mysets 生成器会很高兴地将每个集合按需提供给 reduce 函数,直到它完成。

我相信 reduce 作为 Python 3.0 的内置功能已被弃用,但仍应在 functools 中可用。

您当然可以通过用生成器表达式替换 reduce 中的 mysets 来使其成为单行代码,但这会降低 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(reduce(find_common, mysets))
{'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'}

dict 可以接受任何键值对的迭代器,例如最后返回的元组集合。

于 2008-11-24T16:16:20.100 回答
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。在我看来,这更具可读性,因为这直观地读作“reduce 正在使用集合交集运算符减少此列表”。这也应该快得多,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']
于 2008-11-24T17:22:57.657 回答
2

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

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

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

result = reduce(IntersectDicts, MyList)
于 2008-11-24T16:50:20.467 回答
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'}
于 2008-11-24T20:49:36.770 回答
0

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

于 2008-11-24T16:13:34.957 回答