python 2.6 - 有效地删除和计算字典列表中的重复项

tr3*_*ous 4 python

我正在努力有效地改变:

[{'text': 'hallo world', 'num': 1}, 
 {'text': 'hallo world', 'num': 2}, 
 {'text': 'hallo world', 'num': 1}, 
 {'text': 'haltlo world', 'num': 1}, 
 {'text': 'hallo world', 'num': 1}, 
 {'text': 'hallo world', 'num': 1}, 
 {'text': 'hallo world', 'num': 1}]
Run Code Online (Sandbox Code Playgroud)

到没有重复的字典列表和重复的计数:

[{'text': 'hallo world', 'num': 2, 'count':1}, 
 {'text': 'hallo world', 'num': 1, 'count':5}, 
 {'text': 'haltlo world', 'num': 1, 'count':1}]
Run Code Online (Sandbox Code Playgroud)

到目前为止,我有以下内容来查找重复项:

result = [dict(tupleized) for tupleized in set(tuple(item.items()) for item in li)]
Run Code Online (Sandbox Code Playgroud)

它返回:

[{'text': 'hallo world', 'num': 2}, 
 {'text': 'hallo world', 'num': 1}, 
 {'text': 'haltlo world', 'num': 1}]
Run Code Online (Sandbox Code Playgroud)

谢谢!

Lau*_*low 6

我将使用我的最爱之一itertools

from itertools import groupby

def canonicalize_dict(x):
    "Return a (key, value) list sorted by the hash of the key"
    return sorted(x.items(), key=lambda x: hash(x[0]))

def unique_and_count(lst):
    "Return a list of unique dicts with a 'count' key added"
    grouper = groupby(sorted(map(canonicalize_dict, lst)))
    return [dict(k + [("count", len(list(g)))]) for k, g in grouper]

a = [{'text': 'hallo world', 'num': 1},  
     #....
     {'text': 'hallo world', 'num': 1}]

print unique_and_count(a)
Run Code Online (Sandbox Code Playgroud)

输出

[{'count': 5, 'text': 'hallo world', 'num': 1}, 
{'count': 1, 'text': 'hallo world', 'num': 2}, 
{'count': 1, 'text': 'haltlo world', 'num': 1}]
Run Code Online (Sandbox Code Playgroud)

作为gnibbler指出,d1.items()d2.items()可能有不同的重点排序,即使密钥是相同的,所以我介绍了canonical_dict解决这一问题的功能。


jam*_*lak 6

注意:现在使用frozenset这意味着字典中的项目必须是可清除的.

>>> from collections import defaultdict
>>> from itertools import chain
>>> data = [{'text': 'hallo world', 'num': 1}, {'text': 'hallo world', 'num': 2},  {'text': 'hallo world', 'num': 1}, {'text': 'haltlo world', 'num': 1}, {'text': 'hallo world', 'num': 1}, {'text': 'hallo world', 'num': 1}, {'text': 'hallo world', 'num': 1}]
>>> c = defaultdict(int)
>>> for d in data:
        c[frozenset(d.iteritems())] += 1


>>> [dict(chain(k, (('count', count),))) for k, count in c.iteritems()]
[{'count': 1, 'text': 'haltlo world', 'num': 1}, {'count': 1, 'text': 'hallo world', 'num': 2}, {'count': 5, 'text': 'hallo world', 'num': 1}]
Run Code Online (Sandbox Code Playgroud)