Skip to content

Commit

Permalink
GroupMap: add fold_with
Browse files Browse the repository at this point in the history
This is a generalization of `fold` which takes a function rather than a
value, which removes the need for a `Clone` bound. `fold` is implemented
in terms of `fold_with`.
  • Loading branch information
tamird committed Oct 9, 2023
1 parent 87b41a5 commit 1cee149
Showing 1 changed file with 46 additions and 5 deletions.
51 changes: 46 additions & 5 deletions src/grouping_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,50 @@ where
destination_map
}

/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
/// of each group sequentially, passing the previously accumulated value, a reference to the key
/// and the current element as arguments, and stores the results in a new map.
///
/// `init` is called to obtain the initial value of each accumulator.
///
/// `operation` is a function that is invoked on each element with the following parameters:
/// - the current value of the accumulator of the group;
/// - a reference to the key of the group this element belongs to;
/// - the element from the source being accumulated.
///
/// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
///
/// ```
/// use itertools::Itertools;
///
/// #[derive(Debug, Default)]
/// struct Accumulator {
/// acc: usize,
/// }
///
/// let lookup = (1..=7)
/// .into_grouping_map_by(|&n| n % 3)
/// .fold_with(Default::default, |Accumulator { acc }, _key, val| {
/// let acc = acc + val;
/// Accumulator { acc }
/// });
///
/// assert_eq!(lookup[&0].acc, 3 + 6);
/// assert_eq!(lookup[&1].acc, 1 + 4 + 7);
/// assert_eq!(lookup[&2].acc, 2 + 5);
/// assert_eq!(lookup.len(), 3);
/// ```
pub fn fold_with<FI, FO, R>(self, mut init: FI, mut operation: FO) -> HashMap<K, R>
where
FI: FnMut() -> R,
FO: FnMut(R, &K, V) -> R,
{
self.aggregate(|acc, key, val| {
let acc = acc.unwrap_or_else(&mut init);
Some(operation(acc, key, val))
})
}

/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
/// of each group sequentially, passing the previously accumulated value, a reference to the key
/// and the current element as arguments, and stores the results in a new map.
Expand All @@ -140,15 +184,12 @@ where
/// assert_eq!(lookup[&2], 2 + 5);
/// assert_eq!(lookup.len(), 3);
/// ```
pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
pub fn fold<FO, R>(self, init: R, operation: FO) -> HashMap<K, R>
where
R: Clone,
FO: FnMut(R, &K, V) -> R,
{
self.aggregate(|acc, key, val| {
let acc = acc.unwrap_or_else(|| init.clone());
Some(operation(acc, key, val))
})
self.fold_with(|| init.clone(), operation)
}

/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
Expand Down

0 comments on commit 1cee149

Please sign in to comment.