【问题标题】:Stable Sorting, ie, Minimally-Disruptive Sorting稳定排序,即最小干扰排序
【发布时间】:2011-03-19 07:00:31
【问题描述】:

假设我有一个事物列表(数字,这里为了简单起见),并且我有一个函数,我想使用 SortBy 对它们进行排序。 例如,以下按最后一位数字对数字列表进行排序:

SortBy[{301, 201}, Mod[#,10]&]

并注意这些数字中的两个(即所有)如何具有相同的最后一位数字。 因此,我们以哪种顺序返回它们并不重要。 在这种情况下,Mathematica 以相反的顺序返回它们。 我如何确保打破所有关系,以支持项目在原始列表中的排序方式?

(我知道这有点微不足道,但我觉得这不时出现,所以我认为在 StackOverflow 上获取它会很方便。如果没有人击败,我会发布我想出的任何答案作为答案我给它。)

尝试使其更易于搜索:以最小的干扰进行排序、以最少的交换次数进行排序、自定义平局、以昂贵的交换进行排序、稳定的排序

PS:感谢Nicholas 指出这称为稳定排序。它就在我的舌尖上!这是另一个链接:Link

【问题讨论】:

标签: list sorting wolfram-mathematica utilities


【解决方案1】:

四处打听后,得到了满意的解释:

简短回答:您希望SortBy[list, {f}] 获得稳定的排序。

长答案:

SortBy[list, f] 按通过将 f 应用于列表的每个元素确定的顺序对列表进行排序,使用排序中解释的规范排序来打破平局。 (这是documentation for SortBy 中第二个记录的“更多信息”注释。)

SortBy[list, {f, g}] 使用通过将 g 应用于每个元素确定的顺序来打破平局。

注意SortBy[list, f]SortBy[list, {f, Identity}] 相同。

SortBy[list, {f}] 不会打破平局(并提供稳定的排序),这就是您想要的:

In[13]:= SortBy[{19, 301, 201, 502, 501, 101, 300}, {Mod[#, 10] &}]

Out[13]= {300, 301, 201, 501, 101, 502, 19}

最后,sakra 的解决方案SortBy[list, {f, tie++ &}] 等效于SortBy[list, {f}]

【讨论】:

  • 哇,谢谢你,安德鲁!我读了这篇文章,就像“你刚刚四处打听??你在哪里工作,Wolfram Research?”然后我点击了你的名字,看到你确实这样做了。 :) 我对 StackOverflow 所吸引的专业水平不断感到惊讶。非常感谢您来到这里!
【解决方案2】:

GatherBy 做你想做的事吗?

Flatten[GatherBy[{301, 201, 502, 501, 101}, Mod[#, 10] &]]

【讨论】:

  • 哦,可能是这样,谢谢!我没有想过使用 GatherBy。我倾向于使用订购解决方案。如果您很好奇并想将迄今为止的解决方案与计时测试进行比较,我会让您接受的答案。 (哦,你的解决方案有一个问题:你应该做 Flatten[..., 1] 否则如果元素实际上是列表,那么 Flatten 会毁掉它们。)
  • PS:鉴于已接受的答案,我认为这现在没有实际意义。
【解决方案3】:

SortBy 有一个变体,它通过使用额外的排序函数来打破平局:

SortBy[list,{f1, f2, ...}]

通过计算平局,您可以获得稳定的排序:

Module[{tie = 0}, 
 SortBy[{19, 301, 201, 502, 501, 101, 300}, {Mod[#, 10] &, (tie++) &}]]

产量

{300, 301, 201, 501, 101, 502, 19}

【讨论】:

  • 谢谢,我不知道!事实证明它更简单,正如接受的答案所示。
【解决方案4】:

这似乎有效:

stableSortBy[list_, f_] := 
  SortBy[MapIndexed[List, list], {f@First[#], Last[#]}&][[All,1]]

但现在我看到rosettacode 提供了一种更好的方法:

stableSortBy[list_, f_] := list[[Ordering[f /@ list]]]

所以订购是关键!似乎 Mathematica 文档没有提到排序和排序这个有时很重要的区别。

【讨论】:

  • 这种方法在 Lisp 圈子中被称为“decorate-sort-undecorate”习语,即使GatherBy 可能是特别是稳定排序的最佳方法,它在 Mathematica 中也是一个非常有用的技巧.
  • 我很好奇这在速度方面如何与GatherBy 相提并论,这取决于列表是如何在内部实现的。我的问题是GatherBy 可能只触及每个列表元素一次,而Ordering 解决方案至少需要两次:一次用于排序,一次用于重新排序元素。对于小型列表,这可能无关紧要。但是,在没有实际操作的情况下,我怀疑对于更长的列表 GatherBy 会提供卓越的性能。
  • PS:鉴于已接受的答案,我认为这一切都没有实际意义。
猜你喜欢
  • 2015-06-02
  • 2016-05-23
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 2012-01-03
  • 1970-01-01
  • 2011-06-01
相关资源
最近更新 更多