为啥 Python 的标准库中没有排序容器?

Posted

技术标签:

【中文标题】为啥 Python 的标准库中没有排序容器?【英文标题】:Why are there no sorted containers in Python's standard libraries?为什么 Python 的标准库中没有排序容器? 【发布时间】:2011-08-22 15:09:13 【问题描述】:

是否存在阻止将已排序容器添加到 Python 的 Python 设计决策 (PEP)?

OrderedDict 不是排序容器,因为它是按插入顺序排序的。)

【问题讨论】:

喜欢 collections.OrderedDict? 它只是更快。 O(1) 用于 hashmap 与 O(log n) 用于有序集。 @utdmr:OrderedDict 是按插入顺序排序的,而不是按任意键排序的,例如排序容器。 @Hi-Angel 不,这不是 分类容器 的意思。 E.g. “排序容器是一种在插入时对元素进行排序的容器”。不完全是:我会说排序容器是一个容器,其接口具有有效的排序(根据任意键)迭代和搜索。你的误解源于你不寻常的定义。 【参考方案1】:

还有一个 python sortedcontainers 模块,它实现了排序列表、字典和集合类型。它与 blist 非常相似,但在 pure-Python 中实现,在大多数情况下是 faster。

>>> from sortedcontainers import SortedSet
>>> ss = SortedSet([3, 7, 2, 2])
>>> ss
SortedSet([2, 3, 7])

它还具有其他软件包不常见的功能:

>>> from sortedcontainers import SortedDict
>>> sd = SortedDict((num, num) for num in range(100000))
>>> sd.iloc[-5] # Lookup the fifth-to-last key.
99995

披露:我是 sortedcontainers 模块的作者。

【讨论】:

不错!您可能需要考虑更新文档以指定底层存储为rope。 @NeilG 谢谢!夫妻注意事项: blist 不是用纯 Python 编写的。 sorted set、list 和 dict 类型基于 blist 类型,它是用 C 实现的 B+-tree。此外,底层结构并不是真正的绳索;它更类似于 B+-树,但只有一层节点。 这实际上是一个很好的例子,说明了 big-O 的误导性。它可能会减慢大约一万亿个元素,但大多数人没有 TB 的内存来担心这一点。我在数十亿个元素中对其进行了测试,它与 C 实现一样快。通过维护这种简单的基于列表的结构,它还使用更少的内存。 是的,当然。这与他们用来证明对字符串使用这种数据结构的理由相同,尤其是在编辑器中使用的长字符串。 无论如何,谢谢你写这篇文章。如果我需要这个数据结构,我会记住的。【参考方案2】:

不完全是“排序容器”,但您可能对标准库的 bisect 模块感兴趣,该模块“支持以排序顺序维护列表,而无需在每次插入后对列表进行排序”。

【讨论】:

【参考方案3】:

还有一个blist 模块包含sortedset 数据类型:

sortedset(iterable=(), key=None)

>>> from blist import sortedset
>>> my_set = sortedset([3,7,2,2])
sortedset([2, 3, 7]

【讨论】:

【参考方案4】:

这是 Guido 有意识的设计决定(他甚至对添加 collections 模块有些不情愿)。在为应用程序选择数据类型时,他的目标是保留“一种显而易见的方法”。

基本概念是,如果用户足够成熟,能够意识到内置类型不是解决他们问题的正确解决方案,那么他们也有责任找到合适的第三方库。

鉴于 list+sorting、list+heapq 和 list+bisect 涵盖了许多原本依赖于固有排序数据结构的用例,并且存在诸如 blist 之类的包,因此在这个空间到标准库。

在某些方面,这类似于标准库中没有多维数组,而是将这项任务交给了 NumPy 人员。

【讨论】:

谢谢,我一直在寻找这个设计决策背后的动机。这正是我正在寻找的答案。我最初的直觉不会是这样做,但这个论点很有说服力。 collections.Counter 可以用作排序集。虽然它可能效率不高。 @coderek: collections.Counter 未排序,不适合表示排序集。 但至少不应该对内置字典进行排序?为了提供对元素的快速访问,字典必须按排序存储,这对我来说似乎很奇怪,当你迭代它时,你仍然以某种方式最终得到未排序的项目。 @Hi-Angel dict 是一个哈希表。【参考方案5】:

Python 列表是有序的。如果你对它们进行排序,它们就会保持这种状态。在 Python 2.7 中,添加了一个 OrderedDict 类型来维护一个明确排序的字典。

Python 也有sets(成员必须唯一的集合),但根据定义它们是无序的。对集合进行排序只会返回 list

【讨论】:

感谢您花时间回答。 OrderedDict 按插入顺序排序,而不是像排序容器那样按任意键排序。 set 也不是排序容器。 btree 可能是您正在寻找的吗? ***.com/questions/628192#628432 谢谢,btree 正是我正在寻找的那种东西。我将使用 blist,因为它在 MacPorts 中并且有一堆方便的数据结构。【参考方案6】:

在标准库中有一个heapq,它不是完全排序的,而是排序的。还有一个blist包,但是标准库里没有。

【讨论】:

以上是关于为啥 Python 的标准库中没有排序容器?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C++ 标准库中没有 SIMD 功能?

为啥 C++ 标准库中没有线程池?

标准模板库

python 标准库中的装饰器(特别是@deprecated)

Java - 为啥瞬态成员变量在 Java 标准库中使用如此广泛?

为啥标准库函数中没有提供带有迭代器参数的重载? [复制]