【问题标题】:Python sort parallel arrays in place?Python对并行数组进行排序?
【发布时间】:2010-02-08 15:49:29
【问题描述】:

是否有一种简单的(意味着不滚动自己的排序功能)在 Python 中对并行列表进行排序无需不必要的复制?例如:

foo = range(5)
bar = range(5, 0, -1)
parallelSort(bar, foo)
print foo # [4,3,2,1,0]
print bar # [1,2,3,4,5]

我已经看到使用 zip 的示例,但是如果可以轻松避免,将所有数据从并行列表复制到元组列表并再次返回似乎很愚蠢。

【问题讨论】:

  • 你认为这个parallelSort会做什么?从您的 cmets 看来,它按降序对 foo 进行排序,按升序对 bar 进行排序——对吗?
  • @Paul:它对 b​​ar 进行排序并同步操作 foo。
  • 如果最初 foo[2,4,6,10,8]bar[3,7,9,5,1]parallelSort 会给出什么?
  • @Kenny:bar 现在已排序并等于 [1,3,5,7,9]。 foo 被同步操作,现在等于 [8,2,10,4,6]。

标签: python algorithm sorting


【解决方案1】:

这是一个简单的方法:

perm = sorted(xrange(len(foo)), key=lambda x:foo[x])

这会生成一个排列列表 - perm[i] 中的值是 foo 中第 i 个最小值的索引。然后,您可以按顺序访问这两个列表:

for p in perm:
  print "%s: %s" % (foo[p], bar[p])

不过,您需要对其进行基准测试以了解它是否更有效 - 我怀疑它是否有很大的不同。

【讨论】:

  • 如果您想有所作为,请将 range 更改为 xrange。除非您使用的是 Python 3。
  • 嗯,没错。或者使用 .sort 而不是 sorted,但这会破坏单线性。 ;)
  • 事实证明这并不比将它们异地排序更好,因为sorted 会贪婪地分配大量内存,例如sorted(range(10**6),key=lambda x:x)。 (我的意思是 xrange,它在 python3 中已更改)当您执行此操作时,您会注意到很大一部分 RAM 消失了。事实证明sorted 足够聪明,不会对range 进行排序,所以要注意没有key= 函数的测试。
【解决方案2】:

有没有简单的方法?是的。使用 zip。

是否有“不使用 zip 变体的简单方法”?没有。

如果您想详细说明您反对使用 zip 的原因,那将会很有帮助。要么复制对象,在这种情况下,Python 将通过引用进行复制,要么将一些轻量级的东西复制到轻量级元组中,以至于不值得优化。

如果您真的不关心执行速度,但出于某种原因特别担心内存压力,您可以在您的键列表上滚动您自己的冒泡排序(或您选择的排序算法),这会交换键列表和目标在进行交换时列出元素。我认为这与简单相反,但它肯定会限制您的工作集。

【讨论】:

  • 仅仅因为你想不出一种不使用 zip 的简单方法并不意味着没有 - 请参阅我的答案。 :)
  • 你的答案是用另一个名字压缩,所以我支持“没有不使用 zip 变体的简单方法”。不过,这是一个愚蠢的问题,所以如果在内存中排序本质上是 (sort_value, index) 的元组比排序 (sort_value, target_value) 的元组更可取,很好。
  • “用另一个名字压缩”?当然不是——它与 zipping 没有任何关系,并且根本不修改原始元素。事实上,它甚至没有触及第二个数组。
  • 压缩只是意味着从两个或多个源迭代构建一个元组迭代。你认为 sorted(indices, key=foo) 在做什么?它正在构建 (foo_val, index) 的元组列表,然后对它们进行排序。这与压缩 (foo_val, target_val) 和排序没有区别。
【解决方案3】:

要实现这一点,您必须实现自己的排序。

但是:不必要的复制真的会伤害您的应用程序吗? Python 的某些部分也经常让我觉得效率低下,但它们的效率足以满足我的需要。

【讨论】:

  • 我明白你关于避免过早优化的观点,但有时(这是一种这样的情况)我喜欢编写通用代码并且知道如果我曾经在一个巨大的数据集或其他东西上使用它,它会“只是工作”。在这种情况下,我更担心内存不足而不是速度。
  • 并且不会您自己的排序涉及使用zipdict等吗?
  • 没有。假设您实现了自己的快速排序 - 您可以确保在两个列表上进行任何交换。
  • 我怀疑在 Python 中实现的任何并行排序都会使用更多的时间和更多的内存。 big-O 的速度和空间无法提高,而且在纯 Python 中执行此操作会增加很多开销。
  • @dimcha,如果你有一个大数据集并且内存不足,解决方案可能是这样,但它可能是使用一个numpy数组,或者一个array.array,或者一个数据库,等等。考虑这是否是真正有用的解决方案。
【解决方案4】:

除了从头开始引入排序之外,我能想象到的任何解决方案都使用索引、字典或其他确实不适合节省记忆的东西。无论如何,使用zip 只会将内存使用量增加一个常数因子,因此在解决方案之前确定这确实是一个问题是值得的。

如果确实出现问题,可能会有更有效的解决方案。由于foobar 的元素密切相关,您确定它们的正确表示不是元组列表吗?如果您的内存不足,您确定它们不应该放在更紧凑的数据结构中吗,例如 numpy 数组或数据库(后者非常擅长这种操作)?

(另外,顺便说一下,itertools.izip 可以比zip 节省一点内存,尽管作为排序的结果,您最终仍会以列表形式获得完整的压缩列表。)

【讨论】:

    猜你喜欢
    • 2011-12-26
    • 2021-10-15
    • 1970-01-01
    • 2016-07-26
    • 2013-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多