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

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

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: &quot;Alice&quot;.to_string(),
            championships: 3,
            wins: 17,
        },
        Player {
            name: &quot;Bob&quot;.to_string(),
            championships: 3,
            wins: 19,
        },
        Player {
            name: &quot;Claire&quot;.to_string(),
            championships: 4,
            wins: 18,
        },
        Player {
            name: &quot;Dan&quot;.to_string(),
            championships: 4,
            wins: 18,
        },
    ];
    players.sort_by(|a, b| match b.championships.cmp(&amp;a.championships) {
        Ordering::Less =&gt; Ordering::Less,
        Ordering::Greater =&gt; Ordering::Greater,
        Ordering::Equal =&gt; match b.wins.cmp(&amp;a.wins) {
            Ordering::Less =&gt; Ordering::Less,
            Ordering::Greater =&gt; Ordering::Greater,
            Ordering::Equal =&gt; match a.name.cmp(&amp;b.name) {
                Ordering::Less =&gt; Ordering::Less,
                Ordering::Greater =&gt; Ordering::Greater,
                Ordering::Equal =&gt; Ordering::Equal,
            },
        },
    });
    dbg!(players);
}

This works as intended, as the output shows:

[src/main.rs:46] players = [
    Player {
        name: &quot;Claire&quot;,
        championships: 4,
        wins: 18,
    },
    Player {
        name: &quot;Dan&quot;,
        championships: 4,
        wins: 18,
    },
    Player {
        name: &quot;Bob&quot;,
        championships: 3,
        wins: 19,
    },
    Player {
        name: &quot;Alice&quot;,
        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 =&gt; Ordering::Less,
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) 的用法:

players.sort_by(|a, b| {
    b.championships
        .cmp(&amp;a.championships)
        .then(b.wins.cmp(&amp;a.wins))
        .then(b.name.cmp(&amp;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(&amp;a.championships)
        .then(b.wins.cmp(&amp;a.wins))
        .then(b.name.cmp(&amp;a.name).reverse())
});

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:

确定