about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Micay <danielmicay@gmail.com>2013-05-16 19:29:53 -0400
committerDaniel Micay <danielmicay@gmail.com>2013-05-16 21:51:31 -0400
commit08ef229a65cd7b8de27a5844eee3dce8c69aa846 (patch)
tree86d5c1ed684be5098988a9c5868d0c406d9c11f4
parent00eef96a007a817533e78860e97b251258177d5f (diff)
downloadrust-08ef229a65cd7b8de27a5844eee3dce8c69aa846.tar.gz
rust-08ef229a65cd7b8de27a5844eee3dce8c69aa846.zip
iter: add fold, sum and product
-rw-r--r--src/libcore/iter.rs106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index cfc9afb737c..ae4af3812d2 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -43,6 +43,8 @@ much easier to implement.
 #[cfg(not(stage0))] use cmp::Ord;
 #[cfg(not(stage0))] use option::{Option, Some, None};
 #[cfg(not(stage0))] use vec::OwnedVector;
+#[cfg(not(stage0))] use num::{One, Zero};
+#[cfg(not(stage0))] use ops::{Add, Mul};
 
 #[cfg(stage0)]
 pub trait Times {
@@ -212,6 +214,81 @@ pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
     result
 }
 
+/**
+ * Reduce an iterator to an accumulated value.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline]
+pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T {
+    let mut result = start;
+    for iter |x| {
+        f(&mut result, x);
+    }
+    result
+}
+
+/**
+ * Reduce an iterator to an accumulated value.
+ *
+ * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it
+ * forces the iterator to yield borrowed pointers.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
+ *     fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
+ * }
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline]
+pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T {
+    let mut result = start;
+    for iter |x| {
+        f(&mut result, x);
+    }
+    result
+}
+
+/**
+ * Return the sum of the items yielding by an iterator.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * let xs: ~[int] = ~[1, 2, 3, 4];
+ * assert_eq!(do sum |f| { xs.each(f) }, 10);
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline(always)]
+pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
+    fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x))
+}
+
+/**
+ * Return the product of the items yielded by an iterator.
+ *
+ * # Example:
+ *
+ * ~~~~
+ * let xs: ~[int] = ~[1, 2, 3, 4];
+ * assert_eq!(do product |f| { xs.each(f) }, 24);
+ * ~~~~
+ */
+#[cfg(not(stage0))]
+#[inline(always)]
+pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
+    fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -254,4 +331,33 @@ mod tests {
         let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
         assert_eq!(min(|f| xs.each(f)).unwrap(), &-5);
     }
+
+    #[test]
+    fn test_fold() {
+        assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
+    }
+
+    #[test]
+    fn test_sum() {
+        let xs: ~[int] = ~[1, 2, 3, 4];
+        assert_eq!(do sum |f| { xs.each(f) }, 10);
+    }
+
+    #[test]
+    fn test_empty_sum() {
+        let xs: ~[int] = ~[];
+        assert_eq!(do sum |f| { xs.each(f) }, 0);
+    }
+
+    #[test]
+    fn test_product() {
+        let xs: ~[int] = ~[1, 2, 3, 4];
+        assert_eq!(do product |f| { xs.each(f) }, 24);
+    }
+
+    #[test]
+    fn test_empty_product() {
+        let xs: ~[int] = ~[];
+        assert_eq!(do product |f| { xs.each(f) }, 1);
+    }
 }