How to sort a vector of a custom struct in 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!
Link in the author's blog: https://www.thiagocafe.com/view/20240308_how_to_sort_a_vector_of_a_custom_struct_in_rust/
Top comments (5)
That's a nice simpler alternative, indeed :)
I find it less readable, however.
Why is that? Also, if you are concerned it could be misunderstood, put the lambda in a separate named function called
reverse_order
or something.Now this is on the preference realm. After living many, many years in the low latency world, where things are not super readable, I like explicit things when possible, such as the block:
And, of course, that's my personal preference :) Both are ok - and I agree with you that the function name is better using a descriptive name.
And thanks for the feedback!
Wouldn't it be simpler to
count_b.cmp(count_a)
to change the ordering?