如何从Python中的列表中删除重复的dicts(使用嵌套的dicts)?

时间:2014-01-09 20:38:13

标签: python list dictionary set duplicates

我有一个包含嵌套字典的字典列表,如下所示:

v0 = [ { 'a': 1, 'b': { 'c': 3 } },
       { 'a': 1, 'b': { 'c': 3 }, 'd': 4 },
       { 'a': 1 },
       { 'a': 1, 'b': { 'c': 3 } } ]

如何删除重复的列表元素,结果如下:

v1 = [ { 'a': 1, 'b': { 'c': 3 } },
       { 'a': 1, 'b': { 'c': 3 }, 'd': 4 },
       { 'a': 1 } ]

我不关心秩序,我只想要所有元素的集合。我见过很多类似的问题,但答案只适用于列表中的简单字典,而不是嵌套字典。例如:

v1 = [dict(t) for t in set([tuple(d.items()) for d in v0])]

如果字典没有嵌套,这将有效,但因为它们是,我得到错误“TypeError:unhashable type:'dict'”

3 个答案:

答案 0 :(得分:3)

>>> v0 = [ { 'a': 1, 'b': { 'c': 3 } },
...        { 'a': 1, 'b': { 'c': 3 }, 'd': 4 },
...        { 'a': 1 },
...        { 'a': 1, 'b': { 'c': 3 } } ]
>>> out = []
>>> for v in v0:
...     if v not in out:
...         out.append(v)
...         
>>> out
[{'a': 1, 'b': {'c': 3}}, {'a': 1, 'b': {'c': 3}, 'd': 4}, {'a': 1}]

答案 1 :(得分:1)

首先,考虑一个更简单的想法是否足够好。

如果您的词典集不那么大,那么最后一个词典非常简单 - list已经像set一样工作,除了每次搜索都是线性的而不是恒定时间。所以,相同的代码将采用二次时间而不是线性,但它会起作用,并且它很简单,所以如果这是可以接受的,那就去做吧。

如果你的词典集很大,那么仍然有一个相对简单的选择:基于树的集合(如blistbintrees中的集合可以在对数时间内搜索)。因此,相同的代码将采用对数线性时间而不是线性 - 这通常足够好 - 并且再次起作用,并且简单易行。

如果即使log-linear太慢,那么你需要一个冻结的dict类型和一个递归冻结函数。但是有一些关于PyPI和ActiveState的实现,比如frozendict,并且自己编写一个并不太难。

事实上,你已经到了一半。 set([tuple(d.items()] for d in v0])执行单一级别的冻结,并使用一组元组伪造一个冻结的dict(这对于许多用例不起作用,但对你的用户来说是好的)。所以你只需要递归地做同样的事情。

答案 2 :(得分:0)

如果您对二次算法感到满意,那么

uniq = [x for n, x in enumerate(v0) if v0.index(x) == n]

其他类似

import json
uniq = {json.dumps(x, sort_keys=True):x for x in v0}.values()