1 #![cfg(feature = "use_std")]
2 
3 use crate::{
4     adaptors::map::{MapSpecialCase, MapSpecialCaseFn},
5     MinMaxResult,
6 };
7 use std::cmp::Ordering;
8 use std::collections::HashMap;
9 use std::hash::Hash;
10 use std::iter::Iterator;
11 use std::ops::{Add, Mul};
12 
13 /// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by)
14 pub type MapForGrouping<I, F> = MapSpecialCase<I, GroupingMapFn<F>>;
15 
16 #[derive(Clone)]
17 pub struct GroupingMapFn<F>(F);
18 
19 impl<F> std::fmt::Debug for GroupingMapFn<F> {
20     debug_fmt_fields!(GroupingMapFn,);
21 }
22 
23 impl<V, K, F: FnMut(&V) -> K> MapSpecialCaseFn<V> for GroupingMapFn<F> {
24     type Out = (K, V);
call(&mut self, v: V) -> Self::Out25     fn call(&mut self, v: V) -> Self::Out {
26         ((self.0)(&v), v)
27     }
28 }
29 
new_map_for_grouping<K, I: Iterator, F: FnMut(&I::Item) -> K>( iter: I, key_mapper: F, ) -> MapForGrouping<I, F>30 pub(crate) fn new_map_for_grouping<K, I: Iterator, F: FnMut(&I::Item) -> K>(
31     iter: I,
32     key_mapper: F,
33 ) -> MapForGrouping<I, F> {
34     MapSpecialCase {
35         iter,
36         f: GroupingMapFn(key_mapper),
37     }
38 }
39 
40 /// Creates a new `GroupingMap` from `iter`
new<I, K, V>(iter: I) -> GroupingMap<I> where I: Iterator<Item = (K, V)>, K: Hash + Eq,41 pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
42 where
43     I: Iterator<Item = (K, V)>,
44     K: Hash + Eq,
45 {
46     GroupingMap { iter }
47 }
48 
49 /// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations.
50 ///
51 /// See [`GroupingMap`] for more informations.
52 pub type GroupingMapBy<I, F> = GroupingMap<MapForGrouping<I, F>>;
53 
54 /// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
55 /// It groups elements by their key and at the same time fold each group
56 /// using some aggregating operation.
57 ///
58 /// No method on this struct performs temporary allocations.
59 #[derive(Clone, Debug)]
60 #[must_use = "GroupingMap is lazy and do nothing unless consumed"]
61 pub struct GroupingMap<I> {
62     iter: I,
63 }
64 
65 impl<I, K, V> GroupingMap<I>
66 where
67     I: Iterator<Item = (K, V)>,
68     K: Hash + Eq,
69 {
70     /// This is the generic way to perform any operation on a `GroupingMap`.
71     /// It's suggested to use this method only to implement custom operations
72     /// when the already provided ones are not enough.
73     ///
74     /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
75     /// of each group sequentially, passing the previously accumulated value, a reference to the key
76     /// and the current element as arguments, and stores the results in an `HashMap`.
77     ///
78     /// The `operation` function is invoked on each element with the following parameters:
79     ///  - the current value of the accumulator of the group if there is currently one;
80     ///  - a reference to the key of the group this element belongs to;
81     ///  - the element from the source being aggregated;
82     ///
83     /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
84     /// otherwise the previous accumulation is discarded.
85     ///
86     /// Return a `HashMap` associating the key of each group with the result of aggregation of
87     /// that group's elements. If the aggregation of the last element of a group discards the
88     /// accumulator then there won't be an entry associated to that group's key.
89     ///
90     /// ```
91     /// use itertools::Itertools;
92     ///
93     /// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
94     /// let lookup = data.into_iter()
95     ///     .into_grouping_map_by(|&n| n % 4)
96     ///     .aggregate(|acc, _key, val| {
97     ///         if val == 0 || val == 10 {
98     ///             None
99     ///         } else {
100     ///             Some(acc.unwrap_or(0) + val)
101     ///         }
102     ///     });
103     ///
104     /// assert_eq!(lookup[&0], 4);        // 0 resets the accumulator so only 4 is summed
105     /// assert_eq!(lookup[&1], 5 + 9);
106     /// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
107     /// assert_eq!(lookup[&3], 7);
108     /// assert_eq!(lookup.len(), 3);      // The final keys are only 0, 1 and 2
109     /// ```
aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R> where FO: FnMut(Option<R>, &K, V) -> Option<R>,110     pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
111     where
112         FO: FnMut(Option<R>, &K, V) -> Option<R>,
113     {
114         let mut destination_map = HashMap::new();
115 
116         self.iter.for_each(|(key, val)| {
117             let acc = destination_map.remove(&key);
118             if let Some(op_res) = operation(acc, &key, val) {
119                 destination_map.insert(key, op_res);
120             }
121         });
122 
123         destination_map
124     }
125 
126     /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
127     /// of each group sequentially, passing the previously accumulated value, a reference to the key
128     /// and the current element as arguments, and stores the results in a new map.
129     ///
130     /// `init` is called to obtain the initial value of each accumulator.
131     ///
132     /// `operation` is a function that is invoked on each element with the following parameters:
133     ///  - the current value of the accumulator of the group;
134     ///  - a reference to the key of the group this element belongs to;
135     ///  - the element from the source being accumulated.
136     ///
137     /// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
138     ///
139     /// ```
140     /// use itertools::Itertools;
141     ///
142     /// #[derive(Debug, Default)]
143     /// struct Accumulator {
144     ///   acc: usize,
145     /// }
146     ///
147     /// let lookup = (1..=7)
148     ///     .into_grouping_map_by(|&n| n % 3)
149     ///     .fold_with(|_key, _val| Default::default(), |Accumulator { acc }, _key, val| {
150     ///         let acc = acc + val;
151     ///         Accumulator { acc }
152     ///      });
153     ///
154     /// assert_eq!(lookup[&0].acc, 3 + 6);
155     /// assert_eq!(lookup[&1].acc, 1 + 4 + 7);
156     /// assert_eq!(lookup[&2].acc, 2 + 5);
157     /// assert_eq!(lookup.len(), 3);
158     /// ```
fold_with<FI, FO, R>(self, mut init: FI, mut operation: FO) -> HashMap<K, R> where FI: FnMut(&K, &V) -> R, FO: FnMut(R, &K, V) -> R,159     pub fn fold_with<FI, FO, R>(self, mut init: FI, mut operation: FO) -> HashMap<K, R>
160     where
161         FI: FnMut(&K, &V) -> R,
162         FO: FnMut(R, &K, V) -> R,
163     {
164         self.aggregate(|acc, key, val| {
165             let acc = acc.unwrap_or_else(|| init(key, &val));
166             Some(operation(acc, key, val))
167         })
168     }
169 
170     /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
171     /// of each group sequentially, passing the previously accumulated value, a reference to the key
172     /// and the current element as arguments, and stores the results in a new map.
173     ///
174     /// `init` is the value from which will be cloned the initial value of each accumulator.
175     ///
176     /// `operation` is a function that is invoked on each element with the following parameters:
177     ///  - the current value of the accumulator of the group;
178     ///  - a reference to the key of the group this element belongs to;
179     ///  - the element from the source being accumulated.
180     ///
181     /// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
182     ///
183     /// ```
184     /// use itertools::Itertools;
185     ///
186     /// let lookup = (1..=7)
187     ///     .into_grouping_map_by(|&n| n % 3)
188     ///     .fold(0, |acc, _key, val| acc + val);
189     ///
190     /// assert_eq!(lookup[&0], 3 + 6);
191     /// assert_eq!(lookup[&1], 1 + 4 + 7);
192     /// assert_eq!(lookup[&2], 2 + 5);
193     /// assert_eq!(lookup.len(), 3);
194     /// ```
fold<FO, R>(self, init: R, operation: FO) -> HashMap<K, R> where R: Clone, FO: FnMut(R, &K, V) -> R,195     pub fn fold<FO, R>(self, init: R, operation: FO) -> HashMap<K, R>
196     where
197         R: Clone,
198         FO: FnMut(R, &K, V) -> R,
199     {
200         self.fold_with(|_, _| init.clone(), operation)
201     }
202 
203     /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
204     /// of each group sequentially, passing the previously accumulated value, a reference to the key
205     /// and the current element as arguments, and stores the results in a new map.
206     ///
207     /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
208     ///
209     /// `operation` is a function that is invoked on each element with the following parameters:
210     ///  - the current value of the accumulator of the group;
211     ///  - a reference to the key of the group this element belongs to;
212     ///  - the element from the source being accumulated.
213     ///
214     /// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
215     ///
216     /// [`fold`]: GroupingMap::fold
217     ///
218     /// ```
219     /// use itertools::Itertools;
220     ///
221     /// let lookup = (1..=7)
222     ///     .into_grouping_map_by(|&n| n % 3)
223     ///     .reduce(|acc, _key, val| acc + val);
224     ///
225     /// assert_eq!(lookup[&0], 3 + 6);
226     /// assert_eq!(lookup[&1], 1 + 4 + 7);
227     /// assert_eq!(lookup[&2], 2 + 5);
228     /// assert_eq!(lookup.len(), 3);
229     /// ```
reduce<FO>(self, mut operation: FO) -> HashMap<K, V> where FO: FnMut(V, &K, V) -> V,230     pub fn reduce<FO>(self, mut operation: FO) -> HashMap<K, V>
231     where
232         FO: FnMut(V, &K, V) -> V,
233     {
234         self.aggregate(|acc, key, val| {
235             Some(match acc {
236                 Some(acc) => operation(acc, key, val),
237                 None => val,
238             })
239         })
240     }
241 
242     /// See [`.reduce()`](GroupingMap::reduce).
243     #[deprecated(note = "Use .reduce() instead", since = "0.13.0")]
fold_first<FO>(self, operation: FO) -> HashMap<K, V> where FO: FnMut(V, &K, V) -> V,244     pub fn fold_first<FO>(self, operation: FO) -> HashMap<K, V>
245     where
246         FO: FnMut(V, &K, V) -> V,
247     {
248         self.reduce(operation)
249     }
250 
251     /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
252     /// an instance of `C`. The iteration order is preserved when inserting elements.
253     ///
254     /// Return a `HashMap` associating the key of each group with the collection containing that group's elements.
255     ///
256     /// ```
257     /// use itertools::Itertools;
258     /// use std::collections::HashSet;
259     ///
260     /// let lookup = vec![0, 1, 2, 3, 4, 5, 6, 2, 3, 6].into_iter()
261     ///     .into_grouping_map_by(|&n| n % 3)
262     ///     .collect::<HashSet<_>>();
263     ///
264     /// assert_eq!(lookup[&0], vec![0, 3, 6].into_iter().collect::<HashSet<_>>());
265     /// assert_eq!(lookup[&1], vec![1, 4].into_iter().collect::<HashSet<_>>());
266     /// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::<HashSet<_>>());
267     /// assert_eq!(lookup.len(), 3);
268     /// ```
collect<C>(self) -> HashMap<K, C> where C: Default + Extend<V>,269     pub fn collect<C>(self) -> HashMap<K, C>
270     where
271         C: Default + Extend<V>,
272     {
273         let mut destination_map = HashMap::new();
274 
275         self.iter.for_each(|(key, val)| {
276             destination_map
277                 .entry(key)
278                 .or_insert_with(C::default)
279                 .extend(Some(val));
280         });
281 
282         destination_map
283     }
284 
285     /// Groups elements from the `GroupingMap` source by key and finds the maximum of each group.
286     ///
287     /// If several elements are equally maximum, the last element is picked.
288     ///
289     /// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
290     ///
291     /// ```
292     /// use itertools::Itertools;
293     ///
294     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
295     ///     .into_grouping_map_by(|&n| n % 3)
296     ///     .max();
297     ///
298     /// assert_eq!(lookup[&0], 12);
299     /// assert_eq!(lookup[&1], 7);
300     /// assert_eq!(lookup[&2], 8);
301     /// assert_eq!(lookup.len(), 3);
302     /// ```
max(self) -> HashMap<K, V> where V: Ord,303     pub fn max(self) -> HashMap<K, V>
304     where
305         V: Ord,
306     {
307         self.max_by(|_, v1, v2| V::cmp(v1, v2))
308     }
309 
310     /// Groups elements from the `GroupingMap` source by key and finds the maximum of each group
311     /// with respect to the specified comparison function.
312     ///
313     /// If several elements are equally maximum, the last element is picked.
314     ///
315     /// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
316     ///
317     /// ```
318     /// use itertools::Itertools;
319     ///
320     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
321     ///     .into_grouping_map_by(|&n| n % 3)
322     ///     .max_by(|_key, x, y| y.cmp(x));
323     ///
324     /// assert_eq!(lookup[&0], 3);
325     /// assert_eq!(lookup[&1], 1);
326     /// assert_eq!(lookup[&2], 5);
327     /// assert_eq!(lookup.len(), 3);
328     /// ```
max_by<F>(self, mut compare: F) -> HashMap<K, V> where F: FnMut(&K, &V, &V) -> Ordering,329     pub fn max_by<F>(self, mut compare: F) -> HashMap<K, V>
330     where
331         F: FnMut(&K, &V, &V) -> Ordering,
332     {
333         self.reduce(|acc, key, val| match compare(key, &acc, &val) {
334             Ordering::Less | Ordering::Equal => val,
335             Ordering::Greater => acc,
336         })
337     }
338 
339     /// Groups elements from the `GroupingMap` source by key and finds the element of each group
340     /// that gives the maximum from the specified function.
341     ///
342     /// If several elements are equally maximum, the last element is picked.
343     ///
344     /// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
345     ///
346     /// ```
347     /// use itertools::Itertools;
348     ///
349     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
350     ///     .into_grouping_map_by(|&n| n % 3)
351     ///     .max_by_key(|_key, &val| val % 4);
352     ///
353     /// assert_eq!(lookup[&0], 3);
354     /// assert_eq!(lookup[&1], 7);
355     /// assert_eq!(lookup[&2], 5);
356     /// assert_eq!(lookup.len(), 3);
357     /// ```
max_by_key<F, CK>(self, mut f: F) -> HashMap<K, V> where F: FnMut(&K, &V) -> CK, CK: Ord,358     pub fn max_by_key<F, CK>(self, mut f: F) -> HashMap<K, V>
359     where
360         F: FnMut(&K, &V) -> CK,
361         CK: Ord,
362     {
363         self.max_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
364     }
365 
366     /// Groups elements from the `GroupingMap` source by key and finds the minimum of each group.
367     ///
368     /// If several elements are equally minimum, the first element is picked.
369     ///
370     /// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
371     ///
372     /// ```
373     /// use itertools::Itertools;
374     ///
375     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
376     ///     .into_grouping_map_by(|&n| n % 3)
377     ///     .min();
378     ///
379     /// assert_eq!(lookup[&0], 3);
380     /// assert_eq!(lookup[&1], 1);
381     /// assert_eq!(lookup[&2], 5);
382     /// assert_eq!(lookup.len(), 3);
383     /// ```
min(self) -> HashMap<K, V> where V: Ord,384     pub fn min(self) -> HashMap<K, V>
385     where
386         V: Ord,
387     {
388         self.min_by(|_, v1, v2| V::cmp(v1, v2))
389     }
390 
391     /// Groups elements from the `GroupingMap` source by key and finds the minimum of each group
392     /// with respect to the specified comparison function.
393     ///
394     /// If several elements are equally minimum, the first element is picked.
395     ///
396     /// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
397     ///
398     /// ```
399     /// use itertools::Itertools;
400     ///
401     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
402     ///     .into_grouping_map_by(|&n| n % 3)
403     ///     .min_by(|_key, x, y| y.cmp(x));
404     ///
405     /// assert_eq!(lookup[&0], 12);
406     /// assert_eq!(lookup[&1], 7);
407     /// assert_eq!(lookup[&2], 8);
408     /// assert_eq!(lookup.len(), 3);
409     /// ```
min_by<F>(self, mut compare: F) -> HashMap<K, V> where F: FnMut(&K, &V, &V) -> Ordering,410     pub fn min_by<F>(self, mut compare: F) -> HashMap<K, V>
411     where
412         F: FnMut(&K, &V, &V) -> Ordering,
413     {
414         self.reduce(|acc, key, val| match compare(key, &acc, &val) {
415             Ordering::Less | Ordering::Equal => acc,
416             Ordering::Greater => val,
417         })
418     }
419 
420     /// Groups elements from the `GroupingMap` source by key and finds the element of each group
421     /// that gives the minimum from the specified function.
422     ///
423     /// If several elements are equally minimum, the first element is picked.
424     ///
425     /// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
426     ///
427     /// ```
428     /// use itertools::Itertools;
429     ///
430     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
431     ///     .into_grouping_map_by(|&n| n % 3)
432     ///     .min_by_key(|_key, &val| val % 4);
433     ///
434     /// assert_eq!(lookup[&0], 12);
435     /// assert_eq!(lookup[&1], 4);
436     /// assert_eq!(lookup[&2], 8);
437     /// assert_eq!(lookup.len(), 3);
438     /// ```
min_by_key<F, CK>(self, mut f: F) -> HashMap<K, V> where F: FnMut(&K, &V) -> CK, CK: Ord,439     pub fn min_by_key<F, CK>(self, mut f: F) -> HashMap<K, V>
440     where
441         F: FnMut(&K, &V) -> CK,
442         CK: Ord,
443     {
444         self.min_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
445     }
446 
447     /// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
448     /// each group.
449     ///
450     /// If several elements are equally maximum, the last element is picked.
451     /// If several elements are equally minimum, the first element is picked.
452     ///
453     /// See [`Itertools::minmax`](crate::Itertools::minmax) for the non-grouping version.
454     ///
455     /// Differences from the non grouping version:
456     /// - It never produces a `MinMaxResult::NoElements`
457     /// - It doesn't have any speedup
458     ///
459     /// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
460     ///
461     /// ```
462     /// use itertools::Itertools;
463     /// use itertools::MinMaxResult::{OneElement, MinMax};
464     ///
465     /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
466     ///     .into_grouping_map_by(|&n| n % 3)
467     ///     .minmax();
468     ///
469     /// assert_eq!(lookup[&0], MinMax(3, 12));
470     /// assert_eq!(lookup[&1], MinMax(1, 7));
471     /// assert_eq!(lookup[&2], OneElement(5));
472     /// assert_eq!(lookup.len(), 3);
473     /// ```
minmax(self) -> HashMap<K, MinMaxResult<V>> where V: Ord,474     pub fn minmax(self) -> HashMap<K, MinMaxResult<V>>
475     where
476         V: Ord,
477     {
478         self.minmax_by(|_, v1, v2| V::cmp(v1, v2))
479     }
480 
481     /// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
482     /// each group with respect to the specified comparison function.
483     ///
484     /// If several elements are equally maximum, the last element is picked.
485     /// If several elements are equally minimum, the first element is picked.
486     ///
487     /// It has the same differences from the non-grouping version as `minmax`.
488     ///
489     /// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
490     ///
491     /// ```
492     /// use itertools::Itertools;
493     /// use itertools::MinMaxResult::{OneElement, MinMax};
494     ///
495     /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
496     ///     .into_grouping_map_by(|&n| n % 3)
497     ///     .minmax_by(|_key, x, y| y.cmp(x));
498     ///
499     /// assert_eq!(lookup[&0], MinMax(12, 3));
500     /// assert_eq!(lookup[&1], MinMax(7, 1));
501     /// assert_eq!(lookup[&2], OneElement(5));
502     /// assert_eq!(lookup.len(), 3);
503     /// ```
minmax_by<F>(self, mut compare: F) -> HashMap<K, MinMaxResult<V>> where F: FnMut(&K, &V, &V) -> Ordering,504     pub fn minmax_by<F>(self, mut compare: F) -> HashMap<K, MinMaxResult<V>>
505     where
506         F: FnMut(&K, &V, &V) -> Ordering,
507     {
508         self.aggregate(|acc, key, val| {
509             Some(match acc {
510                 Some(MinMaxResult::OneElement(e)) => {
511                     if compare(key, &val, &e) == Ordering::Less {
512                         MinMaxResult::MinMax(val, e)
513                     } else {
514                         MinMaxResult::MinMax(e, val)
515                     }
516                 }
517                 Some(MinMaxResult::MinMax(min, max)) => {
518                     if compare(key, &val, &min) == Ordering::Less {
519                         MinMaxResult::MinMax(val, max)
520                     } else if compare(key, &val, &max) != Ordering::Less {
521                         MinMaxResult::MinMax(min, val)
522                     } else {
523                         MinMaxResult::MinMax(min, max)
524                     }
525                 }
526                 None => MinMaxResult::OneElement(val),
527                 Some(MinMaxResult::NoElements) => unreachable!(),
528             })
529         })
530     }
531 
532     /// Groups elements from the `GroupingMap` source by key and find the elements of each group
533     /// that gives the minimum and maximum from the specified function.
534     ///
535     /// If several elements are equally maximum, the last element is picked.
536     /// If several elements are equally minimum, the first element is picked.
537     ///
538     /// It has the same differences from the non-grouping version as `minmax`.
539     ///
540     /// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
541     ///
542     /// ```
543     /// use itertools::Itertools;
544     /// use itertools::MinMaxResult::{OneElement, MinMax};
545     ///
546     /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
547     ///     .into_grouping_map_by(|&n| n % 3)
548     ///     .minmax_by_key(|_key, &val| val % 4);
549     ///
550     /// assert_eq!(lookup[&0], MinMax(12, 3));
551     /// assert_eq!(lookup[&1], MinMax(4, 7));
552     /// assert_eq!(lookup[&2], OneElement(5));
553     /// assert_eq!(lookup.len(), 3);
554     /// ```
minmax_by_key<F, CK>(self, mut f: F) -> HashMap<K, MinMaxResult<V>> where F: FnMut(&K, &V) -> CK, CK: Ord,555     pub fn minmax_by_key<F, CK>(self, mut f: F) -> HashMap<K, MinMaxResult<V>>
556     where
557         F: FnMut(&K, &V) -> CK,
558         CK: Ord,
559     {
560         self.minmax_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
561     }
562 
563     /// Groups elements from the `GroupingMap` source by key and sums them.
564     ///
565     /// This is just a shorthand for `self.reduce(|acc, _, val| acc + val)`.
566     /// It is more limited than `Iterator::sum` since it doesn't use the `Sum` trait.
567     ///
568     /// Returns a `HashMap` associating the key of each group with the sum of that group's elements.
569     ///
570     /// ```
571     /// use itertools::Itertools;
572     ///
573     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
574     ///     .into_grouping_map_by(|&n| n % 3)
575     ///     .sum();
576     ///
577     /// assert_eq!(lookup[&0], 3 + 9 + 12);
578     /// assert_eq!(lookup[&1], 1 + 4 + 7);
579     /// assert_eq!(lookup[&2], 5 + 8);
580     /// assert_eq!(lookup.len(), 3);
581     /// ```
sum(self) -> HashMap<K, V> where V: Add<V, Output = V>,582     pub fn sum(self) -> HashMap<K, V>
583     where
584         V: Add<V, Output = V>,
585     {
586         self.reduce(|acc, _, val| acc + val)
587     }
588 
589     /// Groups elements from the `GroupingMap` source by key and multiply them.
590     ///
591     /// This is just a shorthand for `self.reduce(|acc, _, val| acc * val)`.
592     /// It is more limited than `Iterator::product` since it doesn't use the `Product` trait.
593     ///
594     /// Returns a `HashMap` associating the key of each group with the product of that group's elements.
595     ///
596     /// ```
597     /// use itertools::Itertools;
598     ///
599     /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
600     ///     .into_grouping_map_by(|&n| n % 3)
601     ///     .product();
602     ///
603     /// assert_eq!(lookup[&0], 3 * 9 * 12);
604     /// assert_eq!(lookup[&1], 1 * 4 * 7);
605     /// assert_eq!(lookup[&2], 5 * 8);
606     /// assert_eq!(lookup.len(), 3);
607     /// ```
product(self) -> HashMap<K, V> where V: Mul<V, Output = V>,608     pub fn product(self) -> HashMap<K, V>
609     where
610         V: Mul<V, Output = V>,
611     {
612         self.reduce(|acc, _, val| acc * val)
613     }
614 }
615