Need Vec::cmp_by

Let I have two Vec::<T>, named a and b. I want to compare them and get Less or Greater or Equal.
It T implements Ord I can just write a.cmp(&b). But what can I do in opposite case?
Currently I need to write something like this:

for i in 0..min(a.len(), b.len()) {
  let compare_elements = // ... some code comparing a[i] and b[i]
  if compare_elements != Equal {
    return compare_elements;
  }
}
return a.len().cmp(&b.len());

I want to have a method cmp_by(rhs: &Vec<T>, F: Fn(T) -> Ordering) with this usage:

a.cmp_by(&b, |lhs, rhs| 
   // some code comparing lhs and rhs
)

There is an (unfortunately) still unstable Iterator method that gives you (almost) what you are asking for (see this Rust Playground), allowing you to write a.iter().cmp_by(&b, |lhs, rhs| …)

There's no need for a cmp_by() method on all individual collections, as Iterator already has it, albeit nightly.

In the meantime, create a newtype that implements Ord, and map it over the elements, then call cmp().

I’ve considered suggesting this idea, too, but implementing Ord usually involves an aweful lot of boilerplate code.

Here's a demo of the idea.

Try this (untested) Rust Playground

use core::cmp::Ordering;

pub fn cmp_by<T>(a: &[T], b: &[T], f: impl Fn(&T, &T) -> Ordering) -> Ordering {
    let a_len = a.len();
    let b_len = b.len();
    a.iter().zip(b)
        .map(|(x,y)| f(x,y))
        .fold(Ordering::Equal, Ordering::then)
        .then(a_len.cmp(&b_len))
}
6 Likes

Nice use of Ordering::then!

1 Like

Unfortunately, fold will bring the wrong (i.e no) short-circuiting behavior.

1 Like

But maybe this is good

use core::cmp::Ordering;

pub fn cmp_by<T>(a: &[T], b: &[T], mut f: impl FnMut(&T, &T) -> Ordering) -> Ordering {
    a.iter().zip(b)
        .map(|(x, y)| f(x, y))
        .find(|&o| o != Ordering::Equal)
        .unwrap_or_else(|| a.len().cmp(&b.len()))
}

(also untested)

5 Likes

Thanks a lot! I will wait this method, and use some work-around while waiting.

Moderator note: Some of these posts have been deleted after getting off-topic. The question has also been answered, so I'm locking up the thread.

If you have more to add to the thread, "flag" it with the "Something Else" flag and let us know that you want it unlocked.

2 Likes