1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
use core::cmp::Ordering;
/// An extension trait that provides the [`min_max`] method and friends for
/// iterators.
///
/// [`min_max`]: IterMinMax::min_max
#[cfg_attr(docsrs, doc(cfg(feature = "min_max")))]
pub trait IterMinMax: Iterator {
/// Returns the minimum and maximum element in the iterator.
///
/// - If there are no elements then `None` is returned.
/// - In the case of a single element the element is cloned and returned in
/// both places.
/// - If several elements are equally minimum or maximum, the first element
/// is returned.
/// - On an iterator of length `n`, `min_max` does `1.5 * n` comparisons, so
/// it is faster than calling [`min`] and [`max`] separately which does
/// `2 * n` comparisons.
///
/// [`min`]: Iterator::min
/// [`max`]: Iterator::max
fn min_max(self) -> Option<(Self::Item, Self::Item)>
where
Self: Sized,
Self::Item: Ord + Clone,
{
min_max(self, Ord::cmp)
}
/// Returns the minimum and maximum element with respect to the given
/// comparison function.
///
/// See [`min_max`] for more details.
///
/// [`min_max`]: IterMinMax::min_max
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)
}
/// Returns the minimum and maximum element with respect to element returned
/// from the given key function.
///
/// See [`min_max`] for more details.
///
/// [`min_max`]: IterMinMax::min_max
//
// FIXME: `Clone` bound on `K` is unnecessary but requires refactoring
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))
}