-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sort_by
takes a comparison fn, but min_by
/max_by
take a "scoring" fn
#15311
Comments
cc @aturon One possibility could be that |
Has there been any progress on this? I only recently noticed this inconsistency, and it looks like Python 2 provides both |
Key functions would not work well for min/max things without a total order like floats. Ideally you would use comparison based Unfortunately, currently Rust functions cannot return a closure, so creating a |
Scratch that, you actually CAN make a comparing-like function: #![feature(unboxed_closures)]
#![feature(core)]
use std::cmp::Ordering;
pub fn comparing<F,T,B>(f: F) -> Comparing<F> where
F: Fn(&T) -> B,
B: Ord
{
Comparing(f)
}
pub struct Comparing<F>(F);
impl<'a,'b,F,T,B> Fn<(&'a T, &'b T)> for Comparing<F> where
F: Fn(&T) -> B,
B: Ord
{
type Output = Ordering;
extern "rust-call" fn call(&self, args: (&T, &T)) -> Ordering {
self.0(args.0).cmp(&self.0(args.1))
}
}
#[derive(Debug)]
struct A(u8);
fn main() {
let mut a = [A(4), A(2), A(6), A(9)];
a.sort_by(comparing(|x: &A| x.0));
println!("{:?}", a);
} I can't get it to properly infer the parameter to the closure though. This would make it a lot more ergonomic to use a comparator based |
FWIW, Scala also has the |
1.0 beta, P-backcompat-libs, I-needs-decision. |
I'm ✨ 👍 ✨ of having |
2×3 = 6 functions isn't too bad as combinatorial explosion goes, but it still indicates that an important abstraction is missing. For example In this case the clear alternative is Haskell's |
It looks like |
@shepmaster Yes, but you can avoid that cost by using a |
I agree with the "less ergonomic" comment - there's yet another
Maybe if nothing else, maybe this bug can be to just rename and normalize the |
Yeah, i.map(|x| (x, f(x))).max_with(comparing(|(_, h)| h)).map(|(v, _)| v) looks a lot better in Haskell: map fst . maximumBy (comparing snd) $ map (\x -> (x, f x)) i Although the right-to-left data flow always bugged me. Naturally, this code can be made even shorter and less clear. |
Upon thinking more on this, I'm starting to convince myself that the scoring fn variant is not all that useful for Rust unfortunately. For example if you have a people.sort_by(|person| &person.name); Unfortunately you cannot return a reference into the argument passed into the closure, so this will not compile. This means you'll need to either call Additionally, the interaction between There is a downside, however, to not returning All this is basically leading me to:
How does that sound to others? |
For the min/max funcitons it is probably better to introduce a new enum {smaller, greatorOrEqual} or to return an bool. The sort_by function is not very to discover. In servo there is even a other sort function https://github.com/servo/rust-selectors/blob/master/src/quicksort.rs . I think it would be better to leave the api unstable and clean it with an rfc. |
@alexcrichton You've raised some excellent points -- in particular about scoring not being as usable as one might imagine at first. I'm going to take this off the milestone; I think the triage: P-high () |
It would be great if |
Once max_by will be updated, this wrapper will be removed. See rust-lang/rust#15311
I'd like to see this issue resolved as well. It might also make sense to implement |
I wouldn't mind if the function was renamed ( However, I wouldn't want to it to require Clash with |
I would like to see this issue resolved. Usability, clarity, and consistency is more important. It will be great to implement |
I do find scoring useful in practice, personally. I can see how the example "score" of |
We decided in #27724 to go with |
This is sorta inconsistent :(
fn sort_by(self, compare: |&T, &T| -> Ordering)
fn max_by<B: Ord>(&mut self, f: |&A| -> B) -> Option<A>
Having a comparison function is kinda more useful because then you could use
min_by
/max_by
with non-totalOrd
types more easily, but it's also a bit more effort in the easy case. I dunno. fwiw, ruby'ssort_by
takes a "scoring"-like block and haskell'ssortBy
takes a comparison function.The text was updated successfully, but these errors were encountered: