116 lines
3.8 KiB
Rust
116 lines
3.8 KiB
Rust
|
|
/// `MinMaxResult` is an enum returned by `minmax`.
|
|
///
|
|
/// See [`.minmax()`](crate::Itertools::minmax) for more detail.
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum MinMaxResult<T> {
|
|
/// Empty iterator
|
|
NoElements,
|
|
|
|
/// Iterator with one element, so the minimum and maximum are the same
|
|
OneElement(T),
|
|
|
|
/// More than one element in the iterator, the first element is not larger
|
|
/// than the second
|
|
MinMax(T, T)
|
|
}
|
|
|
|
impl<T: Clone> MinMaxResult<T> {
|
|
/// `into_option` creates an `Option` of type `(T, T)`. The returned `Option`
|
|
/// has variant `None` if and only if the `MinMaxResult` has variant
|
|
/// `NoElements`. Otherwise `Some((x, y))` is returned where `x <= y`.
|
|
/// If the `MinMaxResult` has variant `OneElement(x)`, performing this
|
|
/// operation will make one clone of `x`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax};
|
|
///
|
|
/// let r: MinMaxResult<i32> = NoElements;
|
|
/// assert_eq!(r.into_option(), None);
|
|
///
|
|
/// let r = OneElement(1);
|
|
/// assert_eq!(r.into_option(), Some((1, 1)));
|
|
///
|
|
/// let r = MinMax(1, 2);
|
|
/// assert_eq!(r.into_option(), Some((1, 2)));
|
|
/// ```
|
|
pub fn into_option(self) -> Option<(T,T)> {
|
|
match self {
|
|
MinMaxResult::NoElements => None,
|
|
MinMaxResult::OneElement(x) => Some((x.clone(), x)),
|
|
MinMaxResult::MinMax(x, y) => Some((x, y))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Implementation guts for `minmax` and `minmax_by_key`.
|
|
pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F,
|
|
mut lt: L) -> MinMaxResult<I::Item>
|
|
where I: Iterator,
|
|
F: FnMut(&I::Item) -> K,
|
|
L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
|
|
{
|
|
let (mut min, mut max, mut min_key, mut max_key) = match it.next() {
|
|
None => return MinMaxResult::NoElements,
|
|
Some(x) => {
|
|
match it.next() {
|
|
None => return MinMaxResult::OneElement(x),
|
|
Some(y) => {
|
|
let xk = key_for(&x);
|
|
let yk = key_for(&y);
|
|
if !lt(&y, &x, &yk, &xk) {(x, y, xk, yk)} else {(y, x, yk, xk)}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
loop {
|
|
// `first` and `second` are the two next elements we want to look
|
|
// at. We first compare `first` and `second` (#1). The smaller one
|
|
// is then compared to current minimum (#2). The larger one is
|
|
// compared to current maximum (#3). This way we do 3 comparisons
|
|
// for 2 elements.
|
|
let first = match it.next() {
|
|
None => break,
|
|
Some(x) => x
|
|
};
|
|
let second = match it.next() {
|
|
None => {
|
|
let first_key = key_for(&first);
|
|
if lt(&first, &min, &first_key, &min_key) {
|
|
min = first;
|
|
} else if !lt(&first, &max, &first_key, &max_key) {
|
|
max = first;
|
|
}
|
|
break;
|
|
}
|
|
Some(x) => x
|
|
};
|
|
let first_key = key_for(&first);
|
|
let second_key = key_for(&second);
|
|
if !lt(&second, &first, &second_key, &first_key) {
|
|
if lt(&first, &min, &first_key, &min_key) {
|
|
min = first;
|
|
min_key = first_key;
|
|
}
|
|
if !lt(&second, &max, &second_key, &max_key) {
|
|
max = second;
|
|
max_key = second_key;
|
|
}
|
|
} else {
|
|
if lt(&second, &min, &second_key, &min_key) {
|
|
min = second;
|
|
min_key = second_key;
|
|
}
|
|
if !lt(&first, &max, &first_key, &max_key) {
|
|
max = first;
|
|
max_key = first_key;
|
|
}
|
|
}
|
|
}
|
|
|
|
MinMaxResult::MinMax(min, max)
|
|
}
|