use core::cmp::Ordering;
pub trait IterMinMax: Iterator {
fn min_max(self) -> Option<(Self::Item, Self::Item)>
where
Self: Sized,
Self::Item: Ord + Clone,
{
min_max(self, Ord::cmp)
}
fn min_max_by<F>(self, compare: F) -> Option<(Self::Item, Self::Item)>
where
Self: Sized,
Self::Item: Clone,
F: FnMut(&Self::Item, &Self::Item) -> Ordering,
{
min_max(self, compare)
}
fn min_max_by_key<F, K>(self, mut key: F) -> Option<(Self::Item, Self::Item)>
where
Self: Sized,
Self::Item: Clone,
K: Ord + Clone,
F: FnMut(&Self::Item) -> K,
{
self.map(move |item| (key(&item), item))
.min_max_by(|(k1, _), (k2, _)| k1.cmp(k2))
.map(|((_, min), (_, max))| (min, max))
}
}
impl<I: ?Sized> IterMinMax for I where I: Iterator {}
fn min_max<I, F>(mut iter: I, mut compare: F) -> Option<(I::Item, I::Item)>
where
I::Item: Clone,
I: Iterator,
F: FnMut(&I::Item, &I::Item) -> Ordering,
{
let (mut min, mut max) = {
let a = iter.next()?;
match iter.next() {
None => return Some((a.clone(), a)),
Some(b) => match compare(&a, &b) {
Ordering::Less => (a, b),
_ => (b, a),
},
}
};
while let Some(a) = iter.next() {
let b = match iter.next() {
Some(b) => b,
None => {
if compare(&a, &min) == Ordering::Less {
min = a;
} else if compare(&a, &max) == Ordering::Greater {
max = a;
}
break;
}
};
let (a, b) = match compare(&a, &b) {
Ordering::Less => (a, b),
_ => (b, a),
};
if compare(&a, &min) == Ordering::Less {
min = a;
}
if compare(&b, &max) == Ordering::Greater {
max = b;
}
}
Some((min, max))
}