about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorMichael Darakananda <pongad@gmail.com>2014-01-24 22:40:54 -0800
committerMichael Darakananda <pongad@gmail.com>2014-02-01 00:27:28 -0500
commitd088e5fd942c220ae25dfe94af2af566638f4e4f (patch)
tree52af82c486b161abbfdfe2971d28bad2b85e59b9 /src/libstd
parentedfb546e4b2b0aa6dbb6316709b80e034539d09d (diff)
downloadrust-d088e5fd942c220ae25dfe94af2af566638f4e4f.tar.gz
rust-d088e5fd942c220ae25dfe94af2af566638f4e4f.zip
Added minmax function.
Tests ok
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/iter.rs148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs
index 5a38b7cb2e1..194dd12fc75 100644
--- a/src/libstd/iter.rs
+++ b/src/libstd/iter.rs
@@ -882,6 +882,39 @@ pub trait OrdIterator<A> {
     /// assert!(a.iter().min().unwrap() == &1);
     /// ```
     fn min(&mut self) -> Option<A>;
+
+    /// `min_max` finds the mininum and maximum elements in the iterator.
+    ///
+    /// The return type `MinMaxResult` is an enum of three variants:
+    /// - `NoElements` if the iterator is empty.
+    /// - `OneElement(x)` if the iterator has exactly one element.
+    /// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two values are equal if and only if
+    /// there is more than one element in the iterator and all elements are equal.
+    ///
+    /// On an iterator of length `n`, `min_max` does `1.5 * n` comparisons,
+    /// and so faster than calling `min` and `max separately which does `2 * n` comparisons.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::iter::{NoElements, OneElement, MinMax};
+    ///
+    /// let v: [int, ..0] = [];
+    /// assert_eq!(v.iter().min_max(), NoElements);
+    ///
+    /// let v = [1i];
+    /// assert!(v.iter().min_max() == OneElement(&1));
+    ///
+    /// let v = [1i, 2, 3, 4, 5];
+    /// assert!(v.iter().min_max() == MinMax(&1, &5));
+    ///
+    /// let v = [1i, 2, 3, 4, 5, 6];
+    /// assert!(v.iter().min_max() == MinMax(&1, &6));
+    ///
+    /// let v = [1i, 1, 1, 1];
+    /// assert!(v.iter().min_max() == MinMax(&1, &1));
+    /// ```
+    fn min_max(&mut self) -> MinMaxResult<A>;
 }
 
 impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T {
@@ -904,6 +937,91 @@ impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T {
             }
         })
     }
+
+    fn min_max(&mut self) -> MinMaxResult<A> {
+        let (mut min, mut max) = match self.next() {
+            None => return NoElements,
+            Some(x) => {
+                match self.next() {
+                    None => return OneElement(x),
+                    Some(y) => if x < y {(x, y)} else {(y,x)}
+                }
+            }
+        };
+
+        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 mininum (#2). The larger one is compared to current maximum (#3). This
+            // way we do 3 comparisons for 2 elements.
+            let first = match self.next() {
+                None => break,
+                Some(x) => x
+            };
+            let second = match self.next() {
+                None => {
+                    if first < min {
+                        min = first;
+                    } else if first > max {
+                        max = first;
+                    }
+                    break;
+                }
+                Some(x) => x
+            };
+            if first < second {
+                if first < min {min = first;}
+                if max < second {max = second;}
+            } else {
+                if second < min {min = second;}
+                if max < first {max = first;}
+            }
+        }
+
+        MinMax(min, max)
+    }
+}
+
+/// `MinMaxResult` is an enum returned by `min_max`. See `OrdIterator::min_max` for more detail.
+#[deriving(Clone, Eq)]
+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 variant
+    /// `Some(x,y)` is returned where `x <= y`. If `MinMaxResult` has variant `OneElement(x)`,
+    /// performing this operation will make one clone of `x`.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::iter::{NoElements, OneElement, MinMax, MinMaxResult};
+    ///
+    /// let r: MinMaxResult<int> = 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 {
+            NoElements => None,
+            OneElement(x) => Some((x.clone(), x)),
+            MinMax(x, y) => Some((x, y))
+        }
+    }
 }
 
 /// A trait for iterators that are cloneable.
@@ -2944,4 +3062,34 @@ mod tests {
         it.next();
         assert!( it.is_empty() );
     }
+
+    #[test]
+    fn test_min_max() {
+        let v: [int, ..0] = [];
+        assert_eq!(v.iter().min_max(), NoElements);
+
+        let v = [1i];
+        assert!(v.iter().min_max() == OneElement(&1));
+
+        let v = [1i, 2, 3, 4, 5];
+        assert!(v.iter().min_max() == MinMax(&1, &5));
+
+        let v = [1i, 2, 3, 4, 5, 6];
+        assert!(v.iter().min_max() == MinMax(&1, &6));
+
+        let v = [1i, 1, 1, 1];
+        assert!(v.iter().min_max() == MinMax(&1, &1));
+    }
+
+    #[test]
+    fn test_MinMaxResult() {
+        let r: MinMaxResult<int> = 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)));
+    }
 }