-1

Sorting a vector of integers is straight forward as demonstrated here. However, a vector of floats is more complicated due to potential NaN's and floating point operations.

I would like to "combine" the two methods below to get the indicies that would sort a vector of floats, without sorting the actual input vector.

// returns the indices that would sort a vector of ints
fn argsort<T: Ord>(data: &[T]) -> Vec<usize> {
    let mut indices = (0..data.len()).collect::<Vec<_>>();
    indices.sort_by_key(|&i| &data[i]);
    indices
}

and

use std::cmp::Ordering;


// returns a sorted vector of floats that may contain NaNs, with NaNs at the end
fn sort(arr: &Vec<f64>) -> Vec<f64> {
    let mut out = arr.clone();
    out.sort_by(|&a, &b| {
        match (a.is_nan(), b.is_nan()) {
            (true, true) => Ordering::Equal,
            (true, false) => Ordering::Greater,
            (false, true) => Ordering::Less,
            (false, false) => a.partial_cmp(&b).unwrap(),
        }
    });
    return out;
}

How can I return a vector of usize indices that would sort an input vector of floats containing NaNs?

PyRsquared
  • 6,970
  • 11
  • 50
  • 86

2 Answers2

4

i'm not sure if i understood your question. It seems that your second snippet almost answers the question. Is this the answer you were looking for?

   fn sort(arr: &Vec<f64>) -> Vec<usize> {
    let mut out = (0..arr.len()).collect::<Vec<usize>>();
    out.sort_by(|&a_idx, &b_idx| {
        let a = arr[a_idx];
        let b = arr[b_idx];
        match (a.is_nan(), b.is_nan()) {
            (true, true) => Ordering::Equal,
            (true, false) => Ordering::Greater,
            (false, true) => Ordering::Less,
            (false, false) => a.partial_cmp(&b).unwrap(),
        }
    });
    out
}
  • 1
    There is new new-ish [`f64::total_cmp()`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.total_cmp) that makes things quite simpler. – rodrigo Oct 31 '22 at 16:33
0
// construct a tuple vector from the floats, the tuple being (index,float) 
let mut with_indices = arr.clone().into_iter().enumerate()
       .map(|index,value| (index,value)).collect::<Vec<(usize,f64)>>();

// sort the tuple vector by float
with_indices.sort_by(|&a, &b| {
    match (a.1.is_nan(), b.1.is_nan()) {
        (true, true) => Ordering::Equal,
        (true, false) => Ordering::Greater,
        (false, true) => Ordering::Less,
        (false, false) => a.1.partial_cmp(&b.1).unwrap(),
    }
});

// extract the sorted indices from the sorted tuple vector
let stored_indices = with_indices.into_iter().map(|(index,value)| index)
             .collect::<Vec<usize>>();
Oussama Gammoudi
  • 685
  • 7
  • 13