使用有序字典作为有序集

Posted

技术标签:

【中文标题】使用有序字典作为有序集【英文标题】:Using ordered dictionary as ordered set 【发布时间】:2018-12-11 05:51:54 【问题描述】:

现在 Python 3.7 制作了保留顺序的字典 officially part of the language spec 而不是实现细节,我一直在努力思考如何最好地使用这个属性。今天,我发现我需要一个顺序保留集,并认为字典可能会解决问题。

假设我们有一个可散列元素的列表。我们想要一个唯一条目的列表,并且我们希望根据第一次出现来保持这些条目的顺序。一个简单的字典构造函数应该可以解决问题:

ls = "Beautiful is better than ugly. Explicit..."
uniques = list(s:0 for s in ls)

>>> ['B', 'e', 'a', 'u', 't', 'i', 'f', 'l', ' ', 's', 'b', 'r', 'h', 'n', 'g', 'y', '.', 'E', 'x', 'p', 'c']

这将保留第一次出现的顺序并删除所有重复项。

我想知道社区对这个用例和订单保留功能的总体看法。

有什么理由不应该使用这种方法吗? 有没有更好的方法来解决这个问题? 这个方法是 Pythonic 的吗?

通读 Python 之禅,我很矛盾。该方法很简单,但依赖于隐式排序。

请告诉我你的想法。谢谢。

【问题讨论】:

你的问题是什么? “现在字典是保留顺序的……”请记住,这是 CPython 3.6+ 的实现细节,而不是语言特性。 @U9-Forward,每个列举3个问题。 @KlausD。从 3.7 开始,这现在是规范的一部分,因此我们可以依靠它向前发展。 【参考方案1】:

这种使用 Python 3.7 字典作为保留顺序的重复数据删除的方法已经过核心 Python 开发人员 here 的审查。没有比这更好的推荐了。

有什么理由不应该使用这种方法吗?

没有。

有没有更好的方法来解决这个问题?

没有。

这个方法是 Pythonic 的吗?

是的。

该方法很简单,但依赖于隐式排序。

您的问题被标记为 python-3.7。字典保留插入顺序是有保证的,所以这里没有隐式排序。

【讨论】:

谢谢@wim。我没有看到 3.7 更新。那是最好的绿灯。回复:隐含的,我想争辩说,作为规范的一部分仍然不明确。显式看起来更像dict.fromkeys("abc", ordered=True)。有很多行为可能是默认的,但除非你偶然发现,否则你不会知道。 在相当长一段时间内,出于向后兼容性的原因,这仍然是一种非常危险的做法。 @NathanielSaul 好吧,如果你想让它更明确,那么没有什么能阻止你对collections.OrderedDict.fromkeys(...) 做同样的事情。就个人而言,我更喜欢看 dict 理解,只要您不需要支持较旧的 Python 版本。 Hettinger 似乎更像是在建议没有更快的方法来执行任务,不一定建议将其用作未来的首选方法。根据定义,在更广泛的计算机科学世界中,字典仍然被视为对键的顺序一无所知。 Python 核心开发人员可能暂时觉得这无关紧要,但是 10 年后,当有人找到更高效的忽略排序的 dict 实现时呢? @DavidSanders 那我会在 10 年后更新这个答案。【参考方案2】:

这在 Python 3.7 上效果很好!.. 但 Python 3.7 并不是唯一的 Python 版本。在很长一段时间内,依赖 dict 顺序保存将是一个危险的习惯,因为如果您的代码曾经在 3.6 之前的 Python 版本上运行,它将完全静默地停止维护顺序。

例如,依赖dataclassescontextvars 并没有那么危险,因为如果你尝试在没有dataclasses 的Python 上运行依赖dataclasses 的代码,你会得到一个大而清晰的ImportError。失去顺序的字典没有同样的明显性。

您可能不知道它已停止维持秩序。你可能不记得你依赖于 dict 命令。您可能忘记记录或告诉任何人您依赖它,或者您可能是一个可怜的编码员,在没有记录 Python 3.7+ 要求的情况下继承了其他人依赖 dict 顺序的代码。您可能不知道自己忘记在一台特定机器上更新 Python,或者您不小心退出了 Anaconda 或其他任何事情,而您使用的系统 Python 3 仍在使用 3.4。

最终假设 dict 顺序是安全的。现在,尤其是现在,在 3.7 发布几天后,最好使用OrderedDict,或者添加版本检查:

import collections
import sys

_make_ordered_mapping = (dict.fromkeys if sys.version_info >= (3, 7)
                         else collections.OrderedDict.fromkeys)

def ordered_dedup(items):
    return list(_make_ordered_mapping(items))

【讨论】:

以上是关于使用有序字典作为有序集的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:使用有序集的 Windows 函数

Python - 字典到 YAML 转储 - YAML 不扩展有序字典?

python实现字典遍历稳定有序使用collection包OrderedDict

Java中有序集的任何实现?

是否可以交换有序字典的两个键?

如何让字典保持有序