【问题标题】:Large sortable data structures? Dictionary or something else?大型可排序数据结构?字典还是别的?
【发布时间】:2011-02-04 09:13:40
【问题描述】:

我有一个大型 python 字典(65535 个键:值对),其中键是范围(0, 65536),值是整数。

我找到的对该数据结构进行排序的解决方案发布在此处: Sort a Python dictionary by value

该解决方案有效,但不一定很快。

为了使问题进一步复杂化,我有可能拥有许多(数千个)这样的字典,我必须在排序之前将它们组合起来。我目前正在通过迭代一个字典中的对、在另一个字典中进行键查找以及适当地添加/更新条目来组合这些字典。

这使我的问题变成了两个问题:

1) 字典是解决这个问题的正确数据结构吗?自定义树或其他东西更有意义吗?

2)如果字典是明智、合理的选择,那么将字典的倍数组合然后排序的理想方法是什么?

对我来说,一个解决方案可能是重新设计我的程序流程,以便将维护的字典数量减少到一个,尽管这更像是最后的手段。

谢谢

【问题讨论】:

  • 如果键是(连续的)整数,为什么不使用列表呢?
  • 合并字典的步骤似乎可以通过A.update(B) 来实现。
  • 所以我意识到提出问题的更正确方法是“我需要一个键和值都是整数的值排序字典”。它需要基于键:值,因为我想根据值排序,但返回键进行分析。

标签: python sorting dictionary


【解决方案1】:

一个包含 65535 个条目的字典,其中的键来自 (0:65536) 范围,这听起来有点像一个数组。如果您需要排序数组,为什么要使用字典?

通常,在 Python 中,您会为此类数据使用列表。在您的情况下,由于值是整数,您可能还需要考虑使用数组模块。您还应该看看 heapq 模块,因为如果您的数据可以以这种方式表示,则可以使用内置的合并功能。

在任何情况下,如果您需要合并数据结构并生成排序后的数据结构,最好使用合并算法,其中一种可能性是合并排序算法。

【讨论】:

  • 我认为你是对的。我最近一直很“pythonic”(或者至少这是我的借口),以至于我完全忽略了列表很可能更合适的事实。在这种情况下,我总是将 1-65525 作为“键”(尽管该集合不需要完整,但这并不重要)。如果对我有用,我会做一个小测试,然后将其作为答案。
  • 迈克尔,请看我上面的评论。我意识到我需要将键与值耦合,以便我可以根据值排序返回它们。
  • 好的,我明白了。但是,如果您将元组放入列表中,即代替 [3687,3398,22,7464,541,2007] 您将执行 [(0,3687),(1,3398),(2,22),(3, 7464),(4,541),(5,2007)] 那么您可以根据值对列表进行排序,而不会丢失原始列表索引/键。
  • 我将使用元组列表。感谢您的洞察力。如果我有问题,我会报告他们!
  • (奇怪的是,这个答案似乎已被接受,因为评论暗示了我前一天详细解释的完全相同的事情。)
【解决方案2】:

这里没有足够的信息来说明您应该使用哪种数据结构,因为我们不知道您还用它做什么。

如果您需要能够一次快速地将记录插入到数据结构中,那么您确实需要一个树状数据结构,遗憾的是它没有标准实现(甚至没有标准接口,用于某些操作)在 Python 中。

如果您只需要能够按照您所说的去做——对现有数据进行排序——那么您可以使用列表。排序很快,尤其是在部分数据已经排序的情况下,您可以使用二进制搜索进行快速查找。但是,插入元素将是 O(n),而不是像树一样的 O(log n)。

这是一个简单的示例,将字典转换为列表或元组,对组合结果进行排序并使用 bisect 模块搜索项目。

请注意,您可以有重复的键,出现在多个字典中。这很容易处理:它们会自然地排序在一起,二等分会给你一个包含所有这些键的 [start, end) 范围。

如果以后要添加数据块,追加到末尾,重新排序列表; Python 的排序很擅长,它可能会比 O(n log n) 好得多。

如您所说,此代码假定您的键是整数。

dataA = { 1: 'data1', 3: 'data3', 5: 'data5', 2: 'data2' }
dataB = { 2: 'more data2', 4: 'data4', 6: 'data6' }

combined_list = dataA.items() + dataB.items()
combined_list.sort()
print combined_list

import bisect
def get_range(data, value):
    lower_bound = bisect.bisect_left(data, (value, ))
    upper_bound = bisect.bisect_left(data, (value+1, ))
    return lower_bound, upper_bound

lower_bound, upper_bound = get_range(combined_list, 2)
print lower_bound, upper_bound
print combined_list[lower_bound:upper_bound]

【讨论】:

  • 键和值都是整数,我需要对值进行排序(在您的解决方案中仍然有效)。我将对您的答案和迈克尔狄龙的答案进行一些比较。我看到的问题是它没有正确合并数据。我希望在键相同时将值相加。
  • @Locker537:不,这会将相同的键并排放置,这使得合并它们变得简单。
  • 你是对的。当我看到添加 .items 时,我立即下结论。谢谢!
【解决方案3】:

有了这么多数据,我会硬着头皮使用内置的 sqlite 模块。是的,你放弃了一些 python 的灵活性,不得不使用 SQL,但现在它对 65k 值进行排序;接下来将找到满足特定条件的值。因此,与其重新发明关系数据库,不如现在就走 SQL 路线。

【讨论】:

  • 如果您实际上不需要它,这是严重的过度设计。
  • 但是当你看到他想用数千个字典进行查找和更新时,我认为关系方法将是更受支持的选择。下一个必须使用他的代码的人至少有机会了解正在发生的事情。
  • 我同意这种方法有太多的开销和过度设计。不幸的是,我也希望使用最少的额外模块。
猜你喜欢
  • 2017-10-11
  • 2021-08-29
  • 2012-08-01
  • 1970-01-01
  • 2018-12-12
  • 2013-01-18
  • 1970-01-01
  • 2020-03-01
  • 1970-01-01
相关资源
最近更新 更多