【问题标题】:Can I build a list, and sort it at the same time?我可以建立一个列表并同时对其进行排序吗?
【发布时间】:2011-12-22 16:58:29
【问题描述】:

我正在为一个软件编写脚本,但它并不能真正让我直接访问我需要的数据。相反,我需要询问我需要的每条信息,并建立一个我得到的数据列表。由于各种原因,我需要对列表进行排序。只需构建一次列表,然后对其进行排序,然后对其进行处理,这非常容易。但是,我认为将所有内容一次运行会更快,而不是构建列表然后对其进行排序。

所以,目前我基本上得到了这个:

my_list = []

for item in "query for stuff":
    my_list.append("query for %s data" % item)

my_list.sort()

do_stuff(my_list)

“查询东西”位是与软件的查询接口,它会给我一个可迭代的。 my_list 需要包含来自所述可迭代内容的数据列表。通过这样做,我正在查询第一个列表,然后循环遍历它以提取数据并将其放入 my_list。那我整理一下。最后,我正在使用 do_stuff() 方法对其进行处理,该方法将遍历它并对每个项目进行处理。

问题是我不能在排序之前对其进行 do_stuff() 操作,因为列表顺序很重要,原因有很多。我认为我不能避免循环遍历列表两次——一次是构建列表,一次是对其中的每个项目进行处理,因为我们不会提前知道最近在位置 N 添加的项目是否会在我们添加下一个项目之后留在位置 N ——但是以排序的方式插入每个项目似乎更干净,而不是仅仅将它们附加到最后。有点像这样:

for item in "query for stuff":
    my_list.append_sorted(item)

是否值得费心尝试这样做,还是我应该坚持构建列表,然后对其进行排序?

谢谢!

【问题讨论】:

  • 对于那些想要建立一个列表并在一行中排序的人(例如,使用列表理解)使用my_list = sorted( here_is_your_list_comprehension )。 cfstackoverflow.com/questions/11433886/…

标签: python list sorting


【解决方案1】:

简短的回答是:不值得。

看看insertion sort。最坏情况的运行时间是O(n^2)(平均情况也是二次的)。另一方面,Python's sort(也称为Timsort)在最坏的情况下会占用O(n log n)

是的,在插入时保持列表排序确实“看起来”更干净,但这是一个谬误。 它没有真正的好处。唯一考虑使用插入排序的情况是需要在每次插入后显示排序列表。

【讨论】:

  • 这是错误的。如果操作正确,将元素插入排序列表是 O(log(n))。而且,如果您需要在每次插入之间建立一个排序列表,那么保留一个排序列表的效率要高得多。
  • 您正在考虑一个抽象列表。 Python 列表被实现为数组。这意味着在平均情况下插入成本为 O(n),无论您在哪里插入。见wiki.python.org/moin/TimeComplexity
【解决方案2】:

这两种方法在渐进上是等价的。

排序是 O(n lg n) (Python 默认使用 Timsort,除了非常小的数组),在排序列表中插入是 O(lg n) (使用二进制搜索),你必须这样做 n次。

实际上,一种方法或另一种方法可能会稍微快一些,具体取决于您的数据有多少已经排序。

编辑: 我假设在您找到插入点之后在排序列表的中间插入将是恒定时间(即列表的行为类似于链表,即 您将用于此类算法的数据结构)。正如 Sven 所指出的,Python 列表可能不是这种情况。这将使“保持列表排序”的方法 O(n^2),即插入排序。

我说“可能”是因为随着列表的增长,一些列表实现会从数组切换到链表,最值得注意的例子是 CoreFoundation/Cocoa 中的 CFArray/NSArray。 Python 可能会,也可能不会。

【讨论】:

  • 在有序 (Python) 列表中插入是 O(n),而不是 O(log n)。 Python 列表存储为数组。
  • 如何对链表进行二分搜索?您将使用的数据结构是某种平衡树。
  • 我知道的任何 Python 实现中都没有这样的优化。 CPython 的列表实现始终是一个 C 数组,即一块紧密排列的连续内存。 PyPy 的数据结构实现的(令人惊讶的众多)巧妙技巧通常都有文档记录(不保证,但至少提到过),其中没有类似的东西。我不能说 Jython 和 IronPython,但我认为它们的优化工作要少得多,而且对它们来说,只包装底层平台的动态数组类(ArrayList 或其他)要容易得多。
  • 所以保持排序的问题基本上是每次你在位置 N 插入一些东西时,列表中位置 >N 的任何条目都必须移动 +1 ——对吗?而如果您首先构建列表,则只需在最后的一个 .sort() 操作期间移动条目。
  • @SvenMarnach 它不必是一个链表(我说“表现得像一个链表”),它只需要支持最多对数时间的插入。它可能是二叉树,可能是跳过列表等。
【解决方案3】:

看看bisect 模块。它为您提供了维护列表顺序的各种工具。在您的情况下,您可能想使用bisect.insort

for item in query_for_stuff():
    bisect.insort( my_list, "query for %s data" % item )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 2011-12-12
    • 2018-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多