Python 什么';为dicts伪造散列的惯用方法是什么?

Python 什么';为dicts伪造散列的惯用方法是什么?,python,python-3.x,Python,Python 3.x,编辑:正如@BrenBarn所指出的,原文没有意义 给定一个dict列表(由csv.DictReader提供——它们都有str键和值),最好通过将它们全部填充到一个集合中来删除重复项,但这不能直接完成,因为dict是不可散列的。有些人涉及如何为set/dict伪造\uuuu散列(),但没有说明应该首选哪种方式 # i. concise but ugly round trip filtered = [eval(x) for x in {repr(d) for d in pile_o_dicts}]

编辑:正如@BrenBarn所指出的,原文没有意义

给定一个dict列表(由
csv.DictReader
提供——它们都有
str
键和值),最好通过将它们全部填充到一个集合中来删除重复项,但这不能直接完成,因为
dict
是不可散列的。有些人涉及如何为set/dict伪造
\uuuu散列()
,但没有说明应该首选哪种方式

# i. concise but ugly round trip
filtered = [eval(x) for x in {repr(d) for d in pile_o_dicts}]

# ii. wordy but avoids round trip
filtered = []
keys = set()
for d in pile_o_dicts:
    key = str(d)
    if key not in keys:
        keys.add(key)
        filtered.append(d)

# iii. introducing another class for this seems Java-like?
filtered = {hashable_dict(x) for x in pile_o_dicts}

# iv. something else entirely

本着“显而易见的方法是什么”的精神,基于您的示例代码,我认为您的问题和您的字面意思略有不同。实际上,您并不想覆盖
\uuuuuu散列函数()
——您只想在线性时间内过滤掉重复项,对吗?因此,您需要确保每个字典都有以下内容:1)表示每个键值对,2)它们以稳定的顺序表示。您可以使用键值对的排序元组,但我建议使用
frozenset
frozenset
s是可散列的,它们避免了排序的开销,这将提高性能(这似乎证实了这一点)。缺点是它们比元组占用更多的内存,所以这里有一个空间/时间权衡

此外,您的代码使用集合进行过滤,但这没有多大意义。如果您使用字典,则无需执行难看的
eval
步骤:

filtered = {frozenset(d.iteritems()):d for d in pile_o_dicts}.values()
或者在Python 3中,假设您想要的是列表而不是字典视图:

filtered = list({frozenset(d.items()):d for d in pile_o_dicts}.values())
这两个都有点笨重。对于可读性,考虑将其分解成两行:

dict_o_dicts = {frozenset(d.iteritems()):d for d in pile_o_dicts}
filtered = dict_o_dicts.values()
另一种选择是元组的有序元组:

filtered = {tuple(sorted(d.iteritems())):d for d in pile_o_dicts}.values()
最后一点注意:不要为此使用
repr
。计算为相等的词典可以有不同的表示形式:

>>> d1 = {str(i):str(i) for i in range(300)}
>>> d2 = {str(i):str(i) for i in range(299, -1, -1)}
>>> d1 == d2
True
>>> repr(d1) == repr(d2)
False

如果dict都有相同的键,您可以使用
namedtuple

>>> from collections import namedtuple
>>> nt = namedtuple('nt', pile_o_dicts[0])
>>> set(nt(**d) for d in pile_o_dicts)

巧妙命名的pile_o_dicts可通过对其项目列表排序转换为规范形式:

这将把相同的词典分组在一起


FWIW,使用
sorted(d.items())
的技术目前在functools.lru_cache()的标准库中使用,以便识别具有相同关键字参数的函数调用。瞧,这项技术是行之有效的:-)

我不知道你在问什么。您是否正在寻找(即,一个可以用作另一个dict中的键)?您的代码示例没有多大意义(例如,您的第一个示例只是重新创建了原始的
pile_____dicts
)。这并不是首选的解决方案或任何东西,但在您的第一个示例中,您可以通过使用dict理解来避免“往返”评估dict:
{repr(d):pile___dicts中的d代表d}.values()
而不是集合+列表evals@BrenBarn你说得对,被编辑成一些(希望如此!)合理的东西。很难与标准库竞争。
 groups = {}
 for d in pile_o_dicts:
     k = tuple(sorted(d.items()))
     groups.setdefault(k, []).append(d)