Skip to content

Commit d088e5f

Browse files
committed
Added minmax function.
Tests ok
1 parent edfb546 commit d088e5f

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

src/libstd/iter.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,39 @@ pub trait OrdIterator<A> {
882882
/// assert!(a.iter().min().unwrap() == &1);
883883
/// ```
884884
fn min(&mut self) -> Option<A>;
885+
886+
/// `min_max` finds the mininum and maximum elements in the iterator.
887+
///
888+
/// The return type `MinMaxResult` is an enum of three variants:
889+
/// - `NoElements` if the iterator is empty.
890+
/// - `OneElement(x)` if the iterator has exactly one element.
891+
/// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two values are equal if and only if
892+
/// there is more than one element in the iterator and all elements are equal.
893+
///
894+
/// On an iterator of length `n`, `min_max` does `1.5 * n` comparisons,
895+
/// and so faster than calling `min` and `max separately which does `2 * n` comparisons.
896+
///
897+
/// # Example
898+
///
899+
/// ```rust
900+
/// use std::iter::{NoElements, OneElement, MinMax};
901+
///
902+
/// let v: [int, ..0] = [];
903+
/// assert_eq!(v.iter().min_max(), NoElements);
904+
///
905+
/// let v = [1i];
906+
/// assert!(v.iter().min_max() == OneElement(&1));
907+
///
908+
/// let v = [1i, 2, 3, 4, 5];
909+
/// assert!(v.iter().min_max() == MinMax(&1, &5));
910+
///
911+
/// let v = [1i, 2, 3, 4, 5, 6];
912+
/// assert!(v.iter().min_max() == MinMax(&1, &6));
913+
///
914+
/// let v = [1i, 1, 1, 1];
915+
/// assert!(v.iter().min_max() == MinMax(&1, &1));
916+
/// ```
917+
fn min_max(&mut self) -> MinMaxResult<A>;
885918
}
886919

887920
impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T {
@@ -904,6 +937,91 @@ impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T {
904937
}
905938
})
906939
}
940+
941+
fn min_max(&mut self) -> MinMaxResult<A> {
942+
let (mut min, mut max) = match self.next() {
943+
None => return NoElements,
944+
Some(x) => {
945+
match self.next() {
946+
None => return OneElement(x),
947+
Some(y) => if x < y {(x, y)} else {(y,x)}
948+
}
949+
}
950+
};
951+
952+
loop {
953+
// `first` and `second` are the two next elements we want to look at.
954+
// We first compare `first` and `second` (#1). The smaller one is then compared to
955+
// current mininum (#2). The larger one is compared to current maximum (#3). This
956+
// way we do 3 comparisons for 2 elements.
957+
let first = match self.next() {
958+
None => break,
959+
Some(x) => x
960+
};
961+
let second = match self.next() {
962+
None => {
963+
if first < min {
964+
min = first;
965+
} else if first > max {
966+
max = first;
967+
}
968+
break;
969+
}
970+
Some(x) => x
971+
};
972+
if first < second {
973+
if first < min {min = first;}
974+
if max < second {max = second;}
975+
} else {
976+
if second < min {min = second;}
977+
if max < first {max = first;}
978+
}
979+
}
980+
981+
MinMax(min, max)
982+
}
983+
}
984+
985+
/// `MinMaxResult` is an enum returned by `min_max`. See `OrdIterator::min_max` for more detail.
986+
#[deriving(Clone, Eq)]
987+
pub enum MinMaxResult<T> {
988+
/// Empty iterator
989+
NoElements,
990+
991+
/// Iterator with one element, so the minimum and maximum are the same
992+
OneElement(T),
993+
994+
/// More than one element in the iterator, the first element is not larger than the second
995+
MinMax(T, T)
996+
}
997+
998+
impl<T: Clone> MinMaxResult<T> {
999+
/// `into_option` creates an `Option` of type `(T,T)`. The returned `Option` has variant
1000+
/// `None` if and only if the `MinMaxResult` has variant `NoElements`. Otherwise variant
1001+
/// `Some(x,y)` is returned where `x <= y`. If `MinMaxResult` has variant `OneElement(x)`,
1002+
/// performing this operation will make one clone of `x`.
1003+
///
1004+
/// # Example
1005+
///
1006+
/// ```rust
1007+
/// use std::iter::{NoElements, OneElement, MinMax, MinMaxResult};
1008+
///
1009+
/// let r: MinMaxResult<int> = NoElements;
1010+
/// assert_eq!(r.into_option(), None)
1011+
///
1012+
/// let r = OneElement(1);
1013+
/// assert_eq!(r.into_option(), Some((1,1)));
1014+
///
1015+
/// let r = MinMax(1,2);
1016+
/// assert_eq!(r.into_option(), Some((1,2)));
1017+
/// ```
1018+
pub fn into_option(self) -> Option<(T,T)> {
1019+
match self {
1020+
NoElements => None,
1021+
OneElement(x) => Some((x.clone(), x)),
1022+
MinMax(x, y) => Some((x, y))
1023+
}
1024+
}
9071025
}
9081026

9091027
/// A trait for iterators that are cloneable.
@@ -2944,4 +3062,34 @@ mod tests {
29443062
it.next();
29453063
assert!( it.is_empty() );
29463064
}
3065+
3066+
#[test]
3067+
fn test_min_max() {
3068+
let v: [int, ..0] = [];
3069+
assert_eq!(v.iter().min_max(), NoElements);
3070+
3071+
let v = [1i];
3072+
assert!(v.iter().min_max() == OneElement(&1));
3073+
3074+
let v = [1i, 2, 3, 4, 5];
3075+
assert!(v.iter().min_max() == MinMax(&1, &5));
3076+
3077+
let v = [1i, 2, 3, 4, 5, 6];
3078+
assert!(v.iter().min_max() == MinMax(&1, &6));
3079+
3080+
let v = [1i, 1, 1, 1];
3081+
assert!(v.iter().min_max() == MinMax(&1, &1));
3082+
}
3083+
3084+
#[test]
3085+
fn test_MinMaxResult() {
3086+
let r: MinMaxResult<int> = NoElements;
3087+
assert_eq!(r.into_option(), None)
3088+
3089+
let r = OneElement(1);
3090+
assert_eq!(r.into_option(), Some((1,1)));
3091+
3092+
let r = MinMax(1,2);
3093+
assert_eq!(r.into_option(), Some((1,2)));
3094+
}
29473095
}

0 commit comments

Comments
 (0)