英文:
Rust: `sort_by` multiple criteria, verbose pattern matching
问题
Here's the translated code without the translation of the code parts:
我有一个要根据以下标准排序的 `Vector` 玩家:
1. 根据 `championships`(降序)
2. 根据 `wins`(降序)
3. 根据 `name`(升序)
我在 Rust 中实现如下:
```rust
use std::cmp::Ordering;
#[derive(Debug)]
struct Player {
name: String,
championships: u8,
wins: u8,
}
fn main() {
let mut players = vec![
Player {
name: "Alice".to_string(),
championships: 3,
wins: 17,
},
Player {
name: "Bob".to_string(),
championships: 3,
wins: 19,
},
Player {
name: "Claire".to_string(),
championships: 4,
wins: 18,
},
Player {
name: "Dan".to_string(),
championships: 4,
wins: 18,
},
];
players.sort_by(|a, b| match b.championships.cmp(&a.championships) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => match b.wins.cmp(&a.wins) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => match a.name.cmp(&b.name) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => Ordering::Equal,
},
},
});
dbg!(players);
}
这个代码按预期工作,如下所示的输出:
[src/main.rs:46] players = [
Player {
name: "Claire",
championships: 4,
wins: 18,
},
Player {
name: "Dan",
championships: 4,
wins: 18,
},
Player {
name: "Bob",
championships: 3,
wins: 19,
},
Player {
name: "Alice",
championships: 3,
wins: 17,
},
]
然而,模式匹配的代码非常重复,因为在大多数情况下,我只是返回我已经得到的东西,例如:
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
有没有缩短这种冗长的方式的快捷方法?
这不是一个排序问题,而是一个模式匹配问题。(也许可以以更优雅的方式按多个标准排序,但我没有想出如何做,因为我有升序/降序的排序标准。)
<details>
<summary>英文:</summary>
I have a `Vector` of players to be sorted by the following criteria:
1. by `championships` (descending)
2. by `wins` (descending)
3. by `name` (ascending)
I implemented it as follows in Rust:
```rust
use std::cmp::Ordering;
#[derive(Debug)]
struct Player {
name: String,
championships: u8,
wins: u8,
}
fn main() {
let mut players = vec![
Player {
name: "Alice".to_string(),
championships: 3,
wins: 17,
},
Player {
name: "Bob".to_string(),
championships: 3,
wins: 19,
},
Player {
name: "Claire".to_string(),
championships: 4,
wins: 18,
},
Player {
name: "Dan".to_string(),
championships: 4,
wins: 18,
},
];
players.sort_by(|a, b| match b.championships.cmp(&a.championships) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => match b.wins.cmp(&a.wins) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => match a.name.cmp(&b.name) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => Ordering::Equal,
},
},
});
dbg!(players);
}
This works as intended, as the output shows:
[src/main.rs:46] players = [
Player {
name: "Claire",
championships: 4,
wins: 18,
},
Player {
name: "Dan",
championships: 4,
wins: 18,
},
Player {
name: "Bob",
championships: 3,
wins: 19,
},
Player {
name: "Alice",
championships: 3,
wins: 17,
},
]
However, the pattern matching code is very repetitive, because in most cases I just return what I've already got, e.g.:
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Is there any shortcut to avoid this kind of verbosity?
It's not really a sorting problem but a pattern matching problem. (Maybe the sorting by multiple criteria could be done in a more elegant way, which I didn't figure out how to do, given that I have ascending/descending criteria to sort by.)
答案1
得分: 5
以下是翻译好的部分:
使用类似你示例中的链式比较是 std::cmp::Ordering::then
(以及 then_with
) 的用法:
players.sort_by(|a, b| {
b.championships
.cmp(&a.championships)
.then(b.wins.cmp(&a.wins))
.then(b.name.cmp(&a.name).reverse())
});
英文:
Chaining comparisons as in your example is what std::cmp::Ordering::then
(and then_with
) is for:
players.sort_by(|a, b| {
b.championships
.cmp(&a.championships)
.then(b.wins.cmp(&a.wins))
.then(b.name.cmp(&a.name).reverse())
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论