Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rust: `sort_by` multiple criteria, verbose pattern matching

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:

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

[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.)

>Solution :

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())
});
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading