Skip to content

Commit 421ac30

Browse files
committed
Add Itertools::{sum1, product1}
Like fold1, these return Option<T> Some(result) if the iter is nonempty, None otherwise. Allows differentiation between empty iterators and iterators that reduce to neutral elements
1 parent bfe6167 commit 421ac30

File tree

2 files changed

+80
-4
lines changed

2 files changed

+80
-4
lines changed

src/lib.rs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub use either::Either;
3333

3434
#[cfg(feature = "use_std")]
3535
use std::collections::HashMap;
36-
use std::iter::{IntoIterator};
36+
use std::iter::{IntoIterator, once};
3737
use std::cmp::Ordering;
3838
use std::fmt;
3939
#[cfg(feature = "use_std")]
@@ -1762,6 +1762,64 @@ pub trait Itertools : Iterator {
17621762
FoldWhile::Continue(acc)
17631763
}
17641764

1765+
/// Iterates over the entire iterator, adding all the elements
1766+
///
1767+
/// An empty iterator returns `None`, otherwise `Some(sum)`.
1768+
///
1769+
/// # Panics
1770+
///
1771+
/// When calling `sum1()` and a primitive integer type is being returned, this
1772+
/// method will panic if the computation overflows and debug assertions are
1773+
/// enabled.
1774+
///
1775+
/// # Examples
1776+
///
1777+
/// ```
1778+
/// use itertools::Itertools;
1779+
///
1780+
/// let empty_sum = (1..1).sum1::<i32>();
1781+
/// assert_eq!(empty_sum, None);
1782+
///
1783+
/// let nonempty_sum = (1..=10).sum1::<i32>();
1784+
/// assert_eq!(nonempty_sum, Some(55));
1785+
/// ```
1786+
fn sum1<S>(mut self) -> Option<S>
1787+
where Self: Sized,
1788+
S: std::iter::Sum<Self::Item>,
1789+
{
1790+
self.next()
1791+
.map(|first| once(first).chain(self).sum())
1792+
}
1793+
1794+
/// Iterates over the entire iterator, multiplying all the elements
1795+
///
1796+
/// An empty iterator returns `None`, otherwise `Some(product)`.
1797+
///
1798+
/// # Panics
1799+
///
1800+
/// When calling `product1()` and a primitive integer type is being returned,
1801+
/// method will panic if the computation overflows and debug assertions are
1802+
/// enabled.
1803+
///
1804+
/// # Examples
1805+
/// ```
1806+
/// use itertools::Itertools;
1807+
///
1808+
/// let empty_product = (1..1).product1::<i32>();
1809+
/// assert_eq!(empty_product, None);
1810+
///
1811+
/// let nonempty_product = (1..=10).product1::<i32>();
1812+
/// assert_eq!(nonempty_product, Some(3628800));
1813+
/// ```
1814+
fn product1<P>(mut self) -> Option<P>
1815+
where Self: Sized,
1816+
P: std::iter::Product<Self::Item>,
1817+
{
1818+
self.next()
1819+
.map(|first| once(first).chain(self).product())
1820+
}
1821+
1822+
17651823
/// Collect all iterator elements into a sorted vector in ascending order.
17661824
///
17671825
/// **Note:** This consumes the entire iterator, uses the
@@ -1888,13 +1946,13 @@ pub trait Itertools : Iterator {
18881946

18891947
/// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values
18901948
/// are taken from `(Key, Value)` tuple pairs yielded by the input iterator.
1891-
///
1949+
///
18921950
/// ```
18931951
/// use itertools::Itertools;
1894-
///
1952+
///
18951953
/// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)];
18961954
/// let lookup = data.into_iter().into_group_map();
1897-
///
1955+
///
18981956
/// assert_eq!(lookup[&0], vec![10, 20]);
18991957
/// assert_eq!(lookup.get(&1), None);
19001958
/// assert_eq!(lookup[&2], vec![12, 42]);

tests/test_core.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,21 @@ fn tree_fold1() {
238238
assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y));
239239
}
240240
}
241+
242+
#[test]
243+
fn sum1() {
244+
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
245+
assert_eq!(v[..0].iter().cloned().sum1::<i32>(), None);
246+
assert_eq!(v[1..2].iter().cloned().sum1::<i32>(), Some(1));
247+
assert_eq!(v[1..3].iter().cloned().sum1::<i32>(), Some(3));
248+
assert_eq!(v.iter().cloned().sum1::<i32>(), Some(55));
249+
}
250+
251+
#[test]
252+
fn product1() {
253+
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
254+
assert_eq!(v[..0].iter().cloned().product1::<i32>(), None);
255+
assert_eq!(v[..1].iter().cloned().product1::<i32>(), Some(0));
256+
assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
257+
assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
258+
}

0 commit comments

Comments
 (0)