【问题标题】:Add keys in dictionary in SORTED order按 SORTED 顺序在字典中添加键
【发布时间】:2013-03-07 16:14:59
【问题描述】:

假设我有一本字典

{1:5, 2:5, 4:5}

是否有这样的数据结构,如果我添加键值对3:5,将其输入字典以便键按排序顺序?即

{1:5, 2:5, 3:5, 4:5}

我知道collections.OrderedDict(),但这只会使键保持添加顺序(目前这对我来说还不够)。

我不想使用普通字典dic = {},然后必须使用sorted(dic)[0] 来抓取最小的键。我宁愿有 sorted_dict[0] 类型的函数。
这样做的原因是,如果我使用普通字典,我将不得不多次调用排序,因为我会不断地将对添加到我的字典中。

编辑:我应该提到,它不仅是我关心的最小和最大键,我还需要定期打印这本字典......

【问题讨论】:

  • 以我的技能水平,我自己的课会比 sorted(dict) 还要慢!! :(
  • 你需要这个的用例是什么(你试图解决的实际问题)。
  • 一个金融市场应用程序,键是价格,值是该价格的交易量。随着新数据的到来,我必须更新我的字典,并且我想在我的脚本中多次找出最好和最差的价格及其数量。
  • @RedBaron: 每次他需要最小的键时都是 O(N),每次他需要最大的键时都是 O(N),当然每次都是 O(N log N)他需要打印整件事。他在问题中明确表示这是不可接受的。
  • 具体来说,Alex Martelli 对此问题有一个nice answer

标签: python dictionary key sorted


【解决方案1】:

试试这个食谱——http://code.activestate.com/recipes/576998-sorted-dictionary/

它使用 stdlib bisect 模块对键进行排序。

【讨论】:

  • 这行得通,但它不会像为工作使用正确的数据结构那样有效。
  • 还查看了此页面上的链接:stutzbachenterprises.com/blist/sorteddict.html。很好,虽然我在工作,但我不能在那里使用这个模块......
  • @XinLiang: 和我推荐的blist 一样。为什么你不能使用这个模块? (如果您的意思是由于许可不明确,您不能使用 ActiveState 的配方……我之前在一些雇主的法律部门遇到过这个问题,即使我很确定明确的 MIT 许可会覆盖 AS 许可. 但无论如何,blistbintrees 分别是 BSD 许可和 MIT 许可的,所以这不是问题。
  • 我没有安装新模块的权限...另外,我对 python 还是很陌生(3 周经验)
  • @XinLiang:我已经编辑了我的答案来处理这个问题。但我认为对于这个答案,我们在 cmets 上跑题了。
【解决方案2】:

如果您打算连续地从字典中添加和删除键,您确实需要使用适当的数据结构来解决问题的东西——而不是哈希表(或哈希表加列表,如 SortedOrderedDict-类型食谱),但平衡树(或等效的,如跳过列表)。

如果您环顾一下 PyPI,您会发现许多选项。我的建议是blist。尽管它的数据结构可能不如其他一些数据结构那么优化(因为 B+Tree 比二叉树宽得多),但它对于几乎任何你会遇到的用例来说可能已经足够好了。并且它具有完整且经过良好测试的界面,包括经过良好测试的性能保证。其他严肃项目也大量使用它。

如果您正在处理树性能确实很关键的罕见情况之一,您可能应该查看各种红黑树、展开树、跳过列表等实现。我之前用过bintrees,它有一个很棒的接口(例如,你可以通过索引访问键和值,甚至可以对树进行切片,以及将其视为dict,作者已经考虑过了并避免了所有潜在的歧义),但我没有对它进行认真的性能测试。

或者,如果您的键和值确实都是小整数,您可能需要考虑使用 Cython 将 C++ map<int, int> 包装在 Pythonic 接口中。 (在 C++ map 之上提供 complete 接口是不太可能的,但您通常不需要它。)或者,或者,将 bintrees.FastRBTree 之类的实现之一修改为存储并比较 long 而不是 PyObject*

另一方面,如果您只是要一次创建所有字典然后使用它,则有一个更简单的答案。对其进行排序,并将其粘贴在OrderedDict 中。那么你就不需要标准库之外的任何东西了。

sorted_dict = collections.OrderedDict(sorted(d.iteritems()))

从对另一个答案的评论中,您说“我无权安装新模块...”

首先,确保这是真的。您可能确实有权在用户站点包目录中安装模块。或者,如果安装了virtualenv 和/或您正在使用内置venv 的3.3,那么您可能有权创建一个venv 并将模块安装到其中。

但如果是这样,您需要做的是将文件从 blist/bintrees/whatever 复制到您的项目中。

您可能遇到的问题是这些包中的大多数都包含 C 扩展模块,这意味着您必须能够构建它们(嗯,build_ext -i 它们)。如果您的系统没有安装 Python 开发文件和编译器工具链,则不能这样做。在这种情况下,您正在寻找最好的纯 Python 解决方案。 bintrees 带有一个纯 Python 实现,它与普通的 C 扩展实现相同,只是速度较慢。当然,它仍然是 O(log N),只是常数因子要高得多。如果 N 足够大,它仍然是一个巨大的胜利;如果不是,可能不是。

如果这听起来合理,但您需要帮助设置每个用户的站点包或虚拟环境,或将模块复制到您的项目中,或就地构建扩展等,您可能应该搜索现有问题,如果找不到,请提出新问题(如果没有其他原因,只是因为那些擅长安装问题的人不一定是数据结构方面的专家,甚至可能不是正在阅读这个问题)。

【讨论】:

  • 是的,我需要不断地在字典中添加和删除项目,所以我不想每次都使用这个排序功能(n log n)。将调查您的泡罩解决方案
  • PS,如果您使用blist 进行严肃的项目,请给作者 Daniel 发送电子邮件;他喜欢密切关注它是如何被使用的,这样他就可以在某一天推动它包含在 stdlib 中(这显然会让你的生活更轻松,因为你不必再从 PyPI 安装它了)。
  • 不知道blist 包。看完之后,绝对是+1。
【解决方案3】:

晚了一年多,但我想推荐sortedcontainers 模块。与 blist 和 bintrees 一样,它提供了一个 SortedDict 数据类型,以按排序顺序维护键。与那些模块不同,它是用纯 Python 编写的,实际上速度更快。 SortedDict 还支持索引。查找最小值/最大值实际上发生在 O(1) 时间内。

因为它是纯 Python,所以使用 pip 安装应该是一件轻而易举的事:

pip install sortedcontainers

然后你可以简单地导入 SortedDict

In [1]: from sortedcontainers import SortedDict

In [2]: d = SortedDict({1:5, 2:5, 4:5})

In [3]: d
Out[3]: SortedDict({1: 5, 2: 5, 4: 5})

In [4]: d[3] = 5

In [5]: d
Out[5]: SortedDict({1: 5, 2: 5, 3: 5, 4: 5})

如果您在使用 pip 安装东西时遇到困难或者无法复制需要编译的文件,那么您可以将 sortedlist.py 和 sorteddict.py 文件从软件仓库中拉出。所有代码都是open source on github

sortedcontainers 模块还提供了一个performance comparison,其中包含相互比较的最受欢迎的建议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-15
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多