[Thiago Cafe] Programming is fun!

How to sort a vector of a custom struct in Rust

Created by Thiago Guedes on 2024-03-08 04:39:59

Tags: #rust  

When implementing tags for Texted2, I had a list of tags being:

let tags: Vec<(&str, u32)>; // Tag name, number of posts containing this tag

And I need to sort it by the second item of the tuple, the tag count.

Changing the comparing function with a Lambda

As usual, it was simpler than I expected. This is the code to sort

First: Let's say I want to sort from the smaller count to the larger count

 // Adding some types to simplify the reading
freq_list.sort_by(|a: &(&str, u32), b: &(&str, u32)| {
    let (_tag_name_a: &&str, count_a: &u32) = a;
    let (_tag_name_b: &&str, count_b: &u32) = b;
    count_a.cmp(count_b)
});

This is the signature of the method sort_by:

pub fn sort_by<F>(&mut self, mut compare: F)
where
    F: FnMut(&T, &T) -> Ordering,
{
    stable_sort(self, |a, b| compare(a, b) == Less);
}

And Ordering is an enum with the values Less, Equal and Greater

Changing our Lambda to sort in descending order

As the cmp method returns Ordering, to invert the ordering to list the tags from the most common to the least common, it was also quite simple. I just need to invert the Ordering values.

freq_list.sort_by(|a, b| {
    let (_tag_name_a, count_a) = a;
    let (_tag_name_b, count_b) = b;
    match count_a.cmp(count_b) {
        Ordering::Less => Ordering::Greater,
        Ordering::Equal => Ordering::Equal,
        Ordering::Greater => Ordering::Less,
    }
});

Note how clear it is that we're changing the order by using a match block.

I hope it is useful to you and reach me out for any comments!

Tell me your opinion!

Reach me on Twitter - @thiedri