Rust:`sort_by` 多个条件,冗长的模式匹配

huangapple go评论94阅读模式
英文:

Rust: `sort_by` multiple criteria, verbose pattern matching

问题

Here's the translated code without the translation of the code parts:

  1. 我有一个要根据以下标准排序的 `Vector` 玩家:
  2. 1. 根据 `championships`(降序)
  3. 2. 根据 `wins`(降序)
  4. 3. 根据 `name`(升序)
  5. 我在 Rust 中实现如下:
  6. ```rust
  7. use std::cmp::Ordering;
  8. #[derive(Debug)]
  9. struct Player {
  10. name: String,
  11. championships: u8,
  12. wins: u8,
  13. }
  14. fn main() {
  15. let mut players = vec![
  16. Player {
  17. name: "Alice".to_string(),
  18. championships: 3,
  19. wins: 17,
  20. },
  21. Player {
  22. name: "Bob".to_string(),
  23. championships: 3,
  24. wins: 19,
  25. },
  26. Player {
  27. name: "Claire".to_string(),
  28. championships: 4,
  29. wins: 18,
  30. },
  31. Player {
  32. name: "Dan".to_string(),
  33. championships: 4,
  34. wins: 18,
  35. },
  36. ];
  37. players.sort_by(|a, b| match b.championships.cmp(&a.championships) {
  38. Ordering::Less => Ordering::Less,
  39. Ordering::Greater => Ordering::Greater,
  40. Ordering::Equal => match b.wins.cmp(&a.wins) {
  41. Ordering::Less => Ordering::Less,
  42. Ordering::Greater => Ordering::Greater,
  43. Ordering::Equal => match a.name.cmp(&b.name) {
  44. Ordering::Less => Ordering::Less,
  45. Ordering::Greater => Ordering::Greater,
  46. Ordering::Equal => Ordering::Equal,
  47. },
  48. },
  49. });
  50. dbg!(players);
  51. }

这个代码按预期工作,如下所示的输出:

  1. [src/main.rs:46] players = [
  2. Player {
  3. name: "Claire",
  4. championships: 4,
  5. wins: 18,
  6. },
  7. Player {
  8. name: "Dan",
  9. championships: 4,
  10. wins: 18,
  11. },
  12. Player {
  13. name: "Bob",
  14. championships: 3,
  15. wins: 19,
  16. },
  17. Player {
  18. name: "Alice",
  19. championships: 3,
  20. wins: 17,
  21. },
  22. ]

然而,模式匹配的代码非常重复,因为在大多数情况下,我只是返回我已经得到的东西,例如:

  1. Ordering::Less => Ordering::Less,
  2. Ordering::Greater => Ordering::Greater,

有没有缩短这种冗长的方式的快捷方法?

这不是一个排序问题,而是一个模式匹配问题。(也许可以以更优雅的方式按多个标准排序,但我没有想出如何做,因为我有升序/降序的排序标准。)

  1. <details>
  2. <summary>英文:</summary>
  3. I have a `Vector` of players to be sorted by the following criteria:
  4. 1. by `championships` (descending)
  5. 2. by `wins` (descending)
  6. 3. by `name` (ascending)
  7. I implemented it as follows in Rust:
  8. ```rust
  9. use std::cmp::Ordering;
  10. #[derive(Debug)]
  11. struct Player {
  12. name: String,
  13. championships: u8,
  14. wins: u8,
  15. }
  16. fn main() {
  17. let mut players = vec![
  18. Player {
  19. name: &quot;Alice&quot;.to_string(),
  20. championships: 3,
  21. wins: 17,
  22. },
  23. Player {
  24. name: &quot;Bob&quot;.to_string(),
  25. championships: 3,
  26. wins: 19,
  27. },
  28. Player {
  29. name: &quot;Claire&quot;.to_string(),
  30. championships: 4,
  31. wins: 18,
  32. },
  33. Player {
  34. name: &quot;Dan&quot;.to_string(),
  35. championships: 4,
  36. wins: 18,
  37. },
  38. ];
  39. players.sort_by(|a, b| match b.championships.cmp(&amp;a.championships) {
  40. Ordering::Less =&gt; Ordering::Less,
  41. Ordering::Greater =&gt; Ordering::Greater,
  42. Ordering::Equal =&gt; match b.wins.cmp(&amp;a.wins) {
  43. Ordering::Less =&gt; Ordering::Less,
  44. Ordering::Greater =&gt; Ordering::Greater,
  45. Ordering::Equal =&gt; match a.name.cmp(&amp;b.name) {
  46. Ordering::Less =&gt; Ordering::Less,
  47. Ordering::Greater =&gt; Ordering::Greater,
  48. Ordering::Equal =&gt; Ordering::Equal,
  49. },
  50. },
  51. });
  52. dbg!(players);
  53. }

This works as intended, as the output shows:

  1. [src/main.rs:46] players = [
  2. Player {
  3. name: &quot;Claire&quot;,
  4. championships: 4,
  5. wins: 18,
  6. },
  7. Player {
  8. name: &quot;Dan&quot;,
  9. championships: 4,
  10. wins: 18,
  11. },
  12. Player {
  13. name: &quot;Bob&quot;,
  14. championships: 3,
  15. wins: 19,
  16. },
  17. Player {
  18. name: &quot;Alice&quot;,
  19. championships: 3,
  20. wins: 17,
  21. },
  22. ]

However, the pattern matching code is very repetitive, because in most cases I just return what I've already got, e.g.:

  1. Ordering::Less =&gt; Ordering::Less,
  2. Ordering::Greater =&gt; 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) 的用法:

  1. players.sort_by(|a, b| {
  2. b.championships
  3. .cmp(&amp;a.championships)
  4. .then(b.wins.cmp(&amp;a.wins))
  5. .then(b.name.cmp(&amp;a.name).reverse())
  6. });
英文:

Chaining comparisons as in your example is what std::cmp::Ordering::then (and then_with) is for:

  1. players.sort_by(|a, b| {
  2. b.championships
  3. .cmp(&amp;a.championships)
  4. .then(b.wins.cmp(&amp;a.wins))
  5. .then(b.name.cmp(&amp;a.name).reverse())
  6. });

huangapple
  • 本文由 发表于 2023年5月22日 02:10:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76301280.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定