//! 276. Custom comparison min_by() and max_by()
//!
//! `min_by(cmp)` and `max_by(cmp)` take a `Fn(&A, &A) -> Ordering` comparator.
use std::cmp::Ordering;
fn main() {
let floats = [3.14f64, 1.41, 2.71, 1.73, 0.57];
let min_f = floats.iter().copied()
.min_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
let max_f = floats.iter().copied()
.max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
println!("Min float: {:?}", min_f);
println!("Max float: {:?}", max_f);
// Multi-key: min by length, then alphabetical
let words = ["banana", "apple", "fig", "kiwi", "cherry"];
let min_word = words.iter().min_by(|a, b| {
a.len().cmp(&b.len()).then_with(|| a.cmp(b))
});
println!("Min by len then alpha: {:?}", min_word);
// Reverse: find max using min_by with reversed comparator
let nums = [5i32, 2, 8, 1, 9, 3];
let max_via_reversed = nums.iter().min_by(|a, b| b.cmp(a));
println!("Max via reversed min_by: {:?}", max_via_reversed);
// Closest point to origin
#[derive(Debug)]
struct Point { x: f64, y: f64 }
let points = [Point{x:1.0,y:3.0}, Point{x:2.0,y:1.0}, Point{x:0.5,y:2.0}];
let closest = points.iter().min_by(|a, b| {
let da = (a.x*a.x + a.y*a.y).sqrt();
let db = (b.x*b.x + b.y*b.y).sqrt();
da.partial_cmp(&db).unwrap_or(Ordering::Equal)
});
println!("Closest to origin: {:?}", closest);
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
#[test]
fn test_min_by_float() {
let floats = [3.0f64, 1.0, 2.0];
let min = floats.iter().copied()
.min_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
assert_eq!(min, Some(1.0));
}
#[test]
fn test_max_by_reversed() {
let nums = [1i32, 5, 3, 2, 4];
let max = nums.iter().min_by(|a, b| b.cmp(a));
assert_eq!(max, Some(&5));
}
#[test]
fn test_min_by_multi_key() {
let words = ["bb", "aa", "c"];
let min = words.iter().min_by(|a, b| {
a.len().cmp(&b.len()).then_with(|| a.cmp(b))
});
assert_eq!(min, Some(&"c"));
}
}
(* 276. Custom comparison min_by() and max_by() - OCaml *)
let min_by cmp lst =
match lst with
| [] -> None
| x :: xs -> Some (List.fold_left (fun a y -> if cmp y a < 0 then y else a) x xs)
let max_by cmp lst =
match lst with
| [] -> None
| x :: xs -> Some (List.fold_left (fun a y -> if cmp y a > 0 then y else a) x xs)
let () =
let floats = [3.14; 1.41; 2.71; 1.73; 0.57] in
(match min_by Float.compare floats with Some v -> Printf.printf "Min: %.2f\n" v | None -> ());
(match max_by Float.compare floats with Some v -> Printf.printf "Max: %.2f\n" v | None -> ());
let words = ["banana"; "apple"; "fig"; "kiwi"; "cherry"] in
let cmp_len a b =
let c = compare (String.length a) (String.length b) in
if c <> 0 then c else String.compare a b
in
(match min_by cmp_len words with Some w -> Printf.printf "Min by len+alpha: %s\n" w | None -> ());
let nums = [5; 2; 8; 1; 9; 3] in
(match min_by (fun a b -> -compare a b) nums with
| Some n -> Printf.printf "Max via reversed min: %d\n" n
| None -> ())