【问题标题】:Python equivalent to java.util.SortedSet?Python 等价于 java.util.SortedSet?
【发布时间】:2010-10-12 07:23:07
【问题描述】:

有人知道 Python 是否有与 Java 的 SortedSet 接口等效的接口吗?

这就是我要查找的内容:假设我有一个 foo 类型的对象,并且我知道如何比较两个 foo 类型的对象以查看 foo1 是“大于”还是“小于”比“foo2。我想要一种将foo 类型的许多对象存储在列表L 中的方法,这样每当我遍历列表L 时,我都会根据我定义的比较方法按顺序获取对象。

编辑:

我想我每次修改它时都可以使用字典或列表和sort(),但这是最好的方法吗?

【问题讨论】:

  • 好点。最好的意思是“最有效”
  • Python 的排序效率惊人。您必须将其与集合和排序列表进行比较。
  • 基本没有。你需要带上你自己的树。如果您只遍历列表一次,则可以使用答案中描述的 heapq。

标签: python data-structures


【解决方案1】:

看看BTrees。看起来你需要其中之一。据我了解,您需要支持将元素相对便宜地插入存储结构和便宜的排序操作(甚至不支持)的结构。 BTrees 提供了这一点。

我有使用 ZODB.BTrees 的经验,它们可以扩展到成千上万个元素。

【讨论】:

  • 这是正确的实现方式。
【解决方案2】:

您可以使用 bisect 模块中的 insort 在已排序的列表中有效地插入新元素:

from bisect import insort

items = [1,5,7,9]
insort(items, 3)
insort(items, 10)

print items # -> [1, 3, 5, 7, 9, 10]

请注意,这并不直接对应于SortedSet,因为它使用了一个列表。如果您多次插入同一个项目,列表中就会出现重复项。

【讨论】:

  • 终于有人建议使用 O(log n) 实现。 ;)
  • 将其与 O(log n) 二进制搜索 (stackoverflow.com/questions/212358/binary-search-in-python) 相结合,以确保没有重复项。
  • 实际上,插入是 O(n) - 在向量中插入需要在插入点之后移动元素。然而,查找仍然是 O(log(n)),排序迭代只是 O(n)(对于 dict,O(n*log(n)))。
  • 否 - 仅涵盖追加到末尾。过度分配对插入中间没有帮助:您仍然需要将平均 N/2 个项目复制到一个空格,而不必为新元素分配空间。
  • bisect.insort() 如果使用 blist 而不是 python 的标准列表数据类型,则将具有 O(log**2 n) 性能。
【解决方案3】:

如果您正在寻找一种用于 Python 的高效容器类型的实现,它使用平衡搜索树(例如红黑树)之类的东西实现,那么它不是标准库的一部分。

不过我还是找到了这个:

http://www.brpreiss.com/books/opus7/

源代码在这里:

http://www.brpreiss.com/books/opus7/public/Opus7-1.0.tar.gz

我不知道源代码是如何获得许可的,而且我自己也没有使用过,但如果您对滚动自己的容器类不感兴趣,这将是一个很好的起点。

PyAVL 是一个实现 AVL 树的 C 模块。

另外,this thread 可能对您有用。它包含许多关于如何使用 bisect 模块来增强现有 Python 字典以完成您所要求的工作的建议。

当然,以这种方式使用 insort() 进行插入和删除操作会非常昂贵,因此请在您的应用程序中仔细考虑。实现适当的数据结构可能是更好的方法。

在任何情况下,要了解您是否应该对数据结构进行排序或在迭代时对其进行排序,您必须知道您是打算插入很多还是迭代很多。如果您相对不频繁地修改其内容但对其进行大量迭代,则保持数据结构排序是有意义的。相反,如果您一直插入和删除成员,但相对不频繁地迭代集合,则在迭代之前对键集合进行排序会更快。没有一种正确的方法。

【讨论】:

    【解决方案4】:

    与 blist.sortedlist 类似,sortedcontainers 模块提供排序列表、排序集和排序字典数据类型。它在底层实现中使用了修改后的 B-tree,并且在大多数情况下比 blist 更快。

    sortedcontainers 模块是纯 Python 的,所以安装很简单:

    pip install sortedcontainers
    

    那么例如:

    from sortedcontainers import SortedList, SortedDict, SortedSet
    help(SortedList)
    

    sortedcontainers 模块具有 100% 的覆盖率测试和数小时的压力。有一个相当全面的performance comparison 列出了您为此考虑的大部分选项。

    【讨论】:

      【解决方案5】:

      如果您只需要键,而没有关联的值,Python 提供集合:

      s = set(a_list)
      
      for k in sorted(s):
          print k
      

      但是,您每次执行此操作时都会对集合进行排序。 如果开销太大,您可能需要查看HeapQueues。它们可能不那么优雅和“Pythonic”,但也许它们适合您的需求。

      【讨论】:

        【解决方案6】:

        使用blist package 中的blist.sortedlist

        from blist import sortedlist
        
        z = sortedlist([2, 3, 5, 7, 11])
        z.add(6)
        z.add(3)
        z.add(10)
        
        print z
        

        这将输出:

        sortedlist([2, 3, 3, 5, 6, 7, 10, 11])
        

        生成的对象可以像 python 列表一样使用。

        >>> len(z)
        8
        >>> [2 * x for x in z]
        [4, 6, 6, 10, 12, 14, 20, 22]
        

        【讨论】:

          【解决方案7】:

          您是否有可能使用 Jython?我只是提到它是因为使用 TreeMap、TreeSet 等是微不足道的。此外,如果您来自 Java 背景,并且想要朝着 Python 方向前进,那么 Jython 非常适合让转换变得更容易。虽然我认识到在这种情况下使用 TreeSet 不会成为这种“过渡”的一部分。

          对于 Jython 超级用户,我自己有一个问题:无法导入 blist 包,因为它使用了必须导入的 C 文件。但是使用 blist 代替 TreeSet 会有什么好处吗?我们一般可以假设 JVM 使用的算法本质上与 CPython 的算法一样好吗?

          【讨论】:

            猜你喜欢
            • 2012-08-16
            • 2011-02-04
            • 2011-02-11
            • 2015-01-25
            • 2013-04-20
            • 2012-05-11
            • 2021-08-07
            • 2011-11-25
            相关资源
            最近更新 更多