Reputation: 2479
example
struct MyStruct{
row: u8,
column: u8
}
let my_vector = a Vec<MyStruct> with like 100 items in it
Lets say I have a simple setup like this ^. I want to sort my_vector
list of say 100 items by row AND THEN by column so I get my vector looking like sample 1
instead of sample 2
.
sample 1
my_vector = vec![
MyStruct { row: 10, column: 1 },
MyStruct { row: 10, column: 2 },
MyStruct { row: 10, column: 3 }, ]
sample 2
my_vector = vec![
MyStruct { row: 10, column: 3 },
MyStruct { row: 10, column: 1 },
MyStruct { row: 10, column: 2 }, ]
Currently I've been working off this post which describes how to sort by a single key with the sort_by_key()
function, but the issue i'm having with that is that I can only sort by a single key, and not by two or multiple keys. This results in problems like sample 2
, where I get my rows sorted but then my columns in a random order.
I want both my rows and columns to be ordered. How can I do this?, Thanks
Upvotes: 11
Views: 9236
Reputation: 9965
I think using match
is a better alternative because it compares each pair only once. Using sort_unstable_by
might be a bit better because unstable is faster, and because it is possible to make any comparison go in reverse (descending order) -- simply switch a
and b
for that cmp()
call.
struct MyStruct {
row: u8,
column: u8
}
fn sort(items: &mut [MyStruct]) {
items.sort_unstable_by(|a, b| {
match a.row.cmp(&b.row) {
Ordering::Equal => { a.column.cmp(&b.column) }
v => { v }
}
});
}
Upvotes: 2
Reputation: 2479
By collating the information of the previous two solutions and the help of GitHub Copilot, here is a working solution for a sort by two keys
sorting method:
Using the compare
argument on the sort_by
method for a mutable vector:
my_vector.sort_by(| a, b | if a.row == b.row {
a.column.partial_cmp(&b.column).unwrap()
} else {
a.row.partial_cmp(&b.row).unwrap()
});
And using:
println!("{:#?}", locations);
Would output:
let mut locations = vec![
Location {
row: 1,
column: 1
},
Location {
row: 1,
column: 2
},
Location {
row: 2,
column: 1
},
Location {
row: 2,
column: 2
}
];
Upvotes: 5
Reputation: 70980
Since tuples in Rust impl PartialOrd
with lexicographic comparison, you can use the sort_by_key()
methods:
my_vector.sort_unstable_by_key(|item| (item.row, item.column));
Upvotes: 22
Reputation: 76
You can also implement PartialOrd or Ord for MyStruct <module std::CMP>
use core::cmp::Ordering;
#[derive(Debug, Eq, PartialEq, Ord)]
struct MyStruct {
row: u8,
column: u8,
}
impl PartialOrd for MyStruct {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.row == other.row {
return Some(self.column.cmp(&other.column));
}
Some(self.row.cmp(&other.row))
}
}
fn main() {
let mut my_vector = vec![
MyStruct { row: 10, column: 3 },
MyStruct { row: 10, column: 1 },
MyStruct { row: 10, column: 2 },
];
my_vector.sort();
println!("{:?}", my_vector);
}
Upvotes: 5