如何在 Rust 中按降序对 Vector 进行排序?

nnn*_*mmm 20 sorting rust

在 Rust 中,a 的排序方法Vec总是从小到大排列元素。从大到小排序的通用方法是什么?

如果你有一个数字向量,你可以提供一个密钥提取函数,像这样“反转”数字:

let mut numbers: Vec<u32> = vec![100_000, 3, 6, 2];
numbers.sort_by_key(|n| std::u32::MAX - n);
Run Code Online (Sandbox Code Playgroud)

但这不是很清楚,并且将该方法扩展到其他类型(如字符串)并不简单。

nnn*_*mmm 59

至少有三种方法可以做到。

翻转比较功能

vec.sort_by(|a, b| b.cmp(a))
Run Code Online (Sandbox Code Playgroud)

这会切换元素比较的顺序,以便较小的元素在排序函数中显得较大,反之亦然。

具有反向 Ord 实例的包装器

use std::cmp::Reverse;
vec.sort_by_key(|w| Reverse(*w));
Run Code Online (Sandbox Code Playgroud)

Reverse是一个通用包装器,它的Ord实例与包装类型的顺序相反。

如果您尝试Reverse通过删除返回包含引用的*,则会导致生命周期问题,这与直接在内部返回引用时相同sort_by_key(另请参阅此问题)。因此,此代码片段只能与键为Copy类型的向量一起使用。

排序然后反转

vec.sort();
vec.reverse();
Run Code Online (Sandbox Code Playgroud)

它最初以错误的顺序排序,然后反转所有元素。

表现

我用criterion长度 100_000 对这三种方法进行了基准测试Vec<u64>。计时结果按上述顺序列出。左边和右边的值分别显示了置信区间的下限和上限,中间的值是criterion的最佳估计值。

性能相当,虽然翻转比较函数似乎有点慢:

Sorting/sort_1          time:   [6.2189 ms 6.2539 ms 6.2936 ms]
Sorting/sort_2          time:   [6.1828 ms 6.1848 ms 6.1870 ms]
Sorting/sort_3          time:   [6.2090 ms 6.2112 ms 6.2138 ms]
Run Code Online (Sandbox Code Playgroud)

要重现,请将以下文件另存为benches/sort.rsCargo.toml,然后运行cargo bench. 那里有一个额外的基准测试,它检查与排序相比,克隆向量的成本是否无关紧要,它只需要几微秒。

vec.sort_by(|a, b| b.cmp(a))
Run Code Online (Sandbox Code Playgroud)
[package]
name = "sorting_bench"
version = "0.1.0"
authors = ["nnnmmm"]
edition = "2018"

[[bench]]
name = "sort"
harness = false

[dev-dependencies]
criterion = "0.3"
rand = "0.7.3"
Run Code Online (Sandbox Code Playgroud)

  • FWIW 排序然后反向通常并不等同于通过反向比较器排序。比较相等的键的顺序可能不同,这在某些情况下可能很重要。 (11认同)
  • 在这三个中,看起来只有前两个是稳定的。 (5认同)