Skip to content

Commit 340e06f

Browse files
Merge #300
300: Add Itertools::{sum1, product1} r=jswrenn a=Emerentius This implements `sum1` and `product1` consumers that are like `sum` and `product` except they produce an `Option<T>` with `Some` for nonempty iters and `None` otherwise, just like `fold1`. That allows one to distinguish between an empty iter and iters that sum/multiply to their neutral element. Co-authored-by: Emerentius <[email protected]>
2 parents 9b7eefb + 142659f commit 340e06f

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

src/lib.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub use either::Either;
5656

5757
#[cfg(feature = "use_std")]
5858
use std::collections::HashMap;
59-
use std::iter::{IntoIterator};
59+
use std::iter::{IntoIterator, once};
6060
use std::cmp::Ordering;
6161
use std::fmt;
6262
#[cfg(feature = "use_std")]
@@ -1928,6 +1928,64 @@ pub trait Itertools : Iterator {
19281928
FoldWhile::Continue(acc)
19291929
}
19301930

1931+
/// Iterate over the entire iterator and add all the elements.
1932+
///
1933+
/// An empty iterator returns `None`, otherwise `Some(sum)`.
1934+
///
1935+
/// # Panics
1936+
///
1937+
/// When calling `sum1()` and a primitive integer type is being returned, this
1938+
/// method will panic if the computation overflows and debug assertions are
1939+
/// enabled.
1940+
///
1941+
/// # Examples
1942+
///
1943+
/// ```
1944+
/// use itertools::Itertools;
1945+
///
1946+
/// let empty_sum = (1..1).sum1::<i32>();
1947+
/// assert_eq!(empty_sum, None);
1948+
///
1949+
/// let nonempty_sum = (1..11).sum1::<i32>();
1950+
/// assert_eq!(nonempty_sum, Some(55));
1951+
/// ```
1952+
fn sum1<S>(mut self) -> Option<S>
1953+
where Self: Sized,
1954+
S: std::iter::Sum<Self::Item>,
1955+
{
1956+
self.next()
1957+
.map(|first| once(first).chain(self).sum())
1958+
}
1959+
1960+
/// Iterate over the entire iterator and multiply all the elements.
1961+
///
1962+
/// An empty iterator returns `None`, otherwise `Some(product)`.
1963+
///
1964+
/// # Panics
1965+
///
1966+
/// When calling `product1()` and a primitive integer type is being returned,
1967+
/// method will panic if the computation overflows and debug assertions are
1968+
/// enabled.
1969+
///
1970+
/// # Examples
1971+
/// ```
1972+
/// use itertools::Itertools;
1973+
///
1974+
/// let empty_product = (1..1).product1::<i32>();
1975+
/// assert_eq!(empty_product, None);
1976+
///
1977+
/// let nonempty_product = (1..11).product1::<i32>();
1978+
/// assert_eq!(nonempty_product, Some(3628800));
1979+
/// ```
1980+
fn product1<P>(mut self) -> Option<P>
1981+
where Self: Sized,
1982+
P: std::iter::Product<Self::Item>,
1983+
{
1984+
self.next()
1985+
.map(|first| once(first).chain(self).product())
1986+
}
1987+
1988+
19311989
/// Sort all iterator elements into a new iterator in ascending order.
19321990
///
19331991
/// **Note:** This consumes the entire iterator, uses the

tests/test_core.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,21 @@ fn exactly_one() {
252252
assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5));
253253
assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0));
254254
}
255+
256+
#[test]
257+
fn sum1() {
258+
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
259+
assert_eq!(v[..0].iter().cloned().sum1::<i32>(), None);
260+
assert_eq!(v[1..2].iter().cloned().sum1::<i32>(), Some(1));
261+
assert_eq!(v[1..3].iter().cloned().sum1::<i32>(), Some(3));
262+
assert_eq!(v.iter().cloned().sum1::<i32>(), Some(55));
263+
}
264+
265+
#[test]
266+
fn product1() {
267+
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
268+
assert_eq!(v[..0].iter().cloned().product1::<i32>(), None);
269+
assert_eq!(v[..1].iter().cloned().product1::<i32>(), Some(0));
270+
assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
271+
assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
272+
}

0 commit comments

Comments
 (0)