ahmrz
March 15, 2022, 4:36pm
1
Hi,
I am trying to get the indices of a sorted vec of structs which contains float fields. On Stack Overflow, I found a similar question: sorting - How to get the indices that would sort a vector in Rust? - Stack Overflow . However, in my case the struct contains float fields. Here is a sample code of the problem:
struct Player {
power: f64,
weight: f64
}
/* From https://stackoverflow.com/a/69764256 */
fn argsort<T: Ord>(data: &[T]) -> Vec<usize> {
let mut indices = (0..data.len()).collect::<Vec<_>>();
indices.sort_by_key(|&i| &data[i]);
indices
}
fn main() {
let n_players: usize = 2;
let mut players: Vec<Player> = Vec::with_capacity(n_players);
players.push(Player {
power: 10.0,
weight: 50.0
});
players.push(Player {
power: 15.0,
weight: 70.0
});
/* Error */
let indices: Vec<usize> = argsort(&players);
}
I can sort the vector itself using the method mentioned in Sort a Vector - Rust Cookbook .
players.sort_by(|a, b| a.power.partial_cmp(&b.power).unwrap());
But I don't know how I can use the sort_by
function to compare floats in my case. Could someone guide me, on the proper way to integrate the float comparision in the argsort
function above?
Thank you.
You could add an extra argument to compare by. Similar to sort
vs sort_by
β the latter has an additional FnMut(&T, &T) -> Ordering
argument β you can create
fn argsort_by<T, F>(data: &[T], mut compare: F) -> Vec<usize>
where
F: FnMut(&T, &T) -> Ordering,
{
// TODO
}
and then call this as
argsort_by(&players, |a, b| a.power.partial_cmp(&b.power).unwrap())
If you want to come up with the implementation of argsort_by
yourself, give it a go. Otherwise hereβs a solution:
Click to expand.
struct Player {
power: f64,
weight: f64,
}
fn argsort_by<T, F>(data: &[T], mut compare: F) -> Vec<usize>
where
F: FnMut(&T, &T) -> std::cmp::Ordering,
{
let mut indices = (0..data.len()).collect::<Vec<_>>();
indices.sort_by(|&i, &j| compare(&data[i], &data[j]));
indices
}
fn main() {
let n_players: usize = 2;
let mut players: Vec<Player> = Vec::with_capacity(n_players);
players.push(Player {
power: 10.0,
weight: 50.0,
});
players.push(Player {
power: 15.0,
weight: 70.0,
});
let indices: Vec<usize> = argsort_by(&players, |a, b| a.power.partial_cmp(&b.power).unwrap());
dbg!(&indices);
}
alice
March 15, 2022, 4:48pm
3
Assuming that data
is an array of floats:
indices.sort_by(|&i1, &i2| data[i1].partial_cmp(&data[i2]).unwrap())
1 Like
ahmrz
March 15, 2022, 5:28pm
4
Thank you all for the help! I ended up modifying the function as follows:
fn get_sorted_indices(players: &[Player]) -> Vec<usize> {
let mut indices = (0..players.len()).collect::<Vec<_>>();
indices.sort_by(|&a, &b| players[a].power.partial_cmp(&players[b].power).unwrap());
indices
}
system
Closed
June 13, 2022, 5:29pm
5
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.