调用sort降序或仅对列表进行排序并将其反转是否更好?

时间:2017-09-22 23:18:41

标签: list sorting f# reverse

List模块包含sortDescending函数,用于将列表从高到低排序。我读到它只是对列表进行排序然后反转它更快。所以我尝试了,情况似乎就是这样。

 [1.0..1000000.0] |> List.sortDescending;;
Real: 00:00:00.322, CPU: 00:00:00.328, GC gen0: 10, gen1: 4, gen2: 0

[1.0..1000000.0] |> List.sort |> List.rev;;
Real: 00:00:00.243, CPU: 00:00:00.250, GC gen0: 15, gen1: 7, gen2: 0

(我尝试了很多次,这些值很典型)

是否有理由使用sortDescending而不是仅排序列表然后反转结果?

1 个答案:

答案 0 :(得分:4)

目前,对于没有身份的事物(如整数和浮点数),排序和反转应该更快。如果查看video上的源代码(请参阅list.fs和local.fs),则将列表复制到数组中,对数组进行排序,然后重新创建列表。

当您使用sortDescending时,它会使用stableSortInPlaceWith对数组进行排序,stableSortWithKeysAndComparer始终使用stableSortInPlace。排序后,此函数会生成结果的副本并调整重复的项目,使它们按原始顺序排列。这是一个github所以重复的项目不会移动。

排序使用List.sort,它具有优化功能,可以检测没有身份的浮动内容,因此不需要使用稳定排序;没有第二个副本使其更快。如果它是一个对象列表,stableSortWithKeysAndComparer则使用 [1.0..1000000.0] |> List.map Some |> List.sortDescending;; Real: 00:00:13.616, CPU: 00:00:13.275, GC gen0: 146, gen1: 12, gen2: 5 [1.0..1000000.0] |> List.map Some |> List.sort |> List.rev;; Real: 00:00:17.727, CPU: 00:00:17.316, GC gen0: 149, gen1: 15, gen2: 6 ,因此它应该与List.sortDescending的速度相同,但由于反向速度较慢。对于我的测试来说,由于我的虚拟机在共享基础架构上并且给出了截然不同的结果,因此速度较慢但难以确定。

List.sort

正如评论中指出的那样,列表已经排序,使得List.sort |> List.rev快得多(最后我看过,.NET使用快速排序的数组,如果已经排序则速度很快)。但是,即使您首先撤消列表,List.sortDescending仍然比List.sortDescending更快,因为它是双打列表。

还有一点需要注意,这两个实际上并不等同于所有情况。由于它是一个稳定的排序,重复的项目将在List.sort |> List.rev之后按相同的顺序排列,但它们会被{{1}}反转。