]>
git.proxmox.com Git - rustc.git/blob - vendor/itertools/src/grouping_map.rs
1 #![cfg(feature = "use_std")]
3 use crate::MinMaxResult
;
4 use std
::cmp
::Ordering
;
5 use std
::collections
::HashMap
;
7 use std
::iter
::Iterator
;
8 use std
::ops
::{Add, Mul}
;
10 /// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by)
11 #[derive(Clone, Debug)]
12 pub struct MapForGrouping
<I
, F
>(I
, F
);
14 impl<I
, F
> MapForGrouping
<I
, F
> {
15 pub(crate) fn new(iter
: I
, key_mapper
: F
) -> Self {
16 Self(iter
, key_mapper
)
20 impl<K
, V
, I
, F
> Iterator
for MapForGrouping
<I
, F
>
22 I
: Iterator
<Item
= V
>,
27 fn next(&mut self) -> Option
<Self::Item
> {
28 self.0.next().map(|val
| ((self.1)(&val
), val
))
32 /// Creates a new `GroupingMap` from `iter`
33 pub fn new
<I
, K
, V
>(iter
: I
) -> GroupingMap
<I
>
35 I
: Iterator
<Item
= (K
, V
)>,
41 /// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations.
43 /// See [`GroupingMap`] for more informations.
44 pub type GroupingMapBy
<I
, F
> = GroupingMap
<MapForGrouping
<I
, F
>>;
46 /// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
47 /// It groups elements by their key and at the same time fold each group
48 /// using some aggregating operation.
50 /// No method on this struct performs temporary allocations.
51 #[derive(Clone, Debug)]
52 #[must_use = "GroupingMap is lazy and do nothing unless consumed"]
53 pub struct GroupingMap
<I
> {
57 impl<I
, K
, V
> GroupingMap
<I
>
59 I
: Iterator
<Item
= (K
, V
)>,
62 /// This is the generic way to perform any operation on a `GroupingMap`.
63 /// It's suggested to use this method only to implement custom operations
64 /// when the already provided ones are not enough.
66 /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
67 /// of each group sequentially, passing the previously accumulated value, a reference to the key
68 /// and the current element as arguments, and stores the results in an `HashMap`.
70 /// The `operation` function is invoked on each element with the following parameters:
71 /// - the current value of the accumulator of the group if there is currently one;
72 /// - a reference to the key of the group this element belongs to;
73 /// - the element from the source being aggregated;
75 /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
76 /// otherwise the previous accumulation is discarded.
78 /// Return a `HashMap` associating the key of each group with the result of aggregation of
79 /// that group's elements. If the aggregation of the last element of a group discards the
80 /// accumulator then there won't be an entry associated to that group's key.
83 /// use itertools::Itertools;
85 /// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
86 /// let lookup = data.into_iter()
87 /// .into_grouping_map_by(|&n| n % 4)
88 /// .aggregate(|acc, _key, val| {
89 /// if val == 0 || val == 10 {
92 /// Some(acc.unwrap_or(0) + val)
96 /// assert_eq!(lookup[&0], 4); // 0 resets the accumulator so only 4 is summed
97 /// assert_eq!(lookup[&1], 5 + 9);
98 /// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
99 /// assert_eq!(lookup[&3], 7);
100 /// assert_eq!(lookup.len(), 3); // The final keys are only 0, 1 and 2
102 pub fn aggregate
<FO
, R
>(self, mut operation
: FO
) -> HashMap
<K
, R
>
104 FO
: FnMut(Option
<R
>, &K
, V
) -> Option
<R
>,
106 let mut destination_map
= HashMap
::new();
108 self.iter
.for_each(|(key
, val
)| {
109 let acc
= destination_map
.remove(&key
);
110 if let Some(op_res
) = operation(acc
, &key
, val
) {
111 destination_map
.insert(key
, op_res
);
118 /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
119 /// of each group sequentially, passing the previously accumulated value, a reference to the key
120 /// and the current element as arguments, and stores the results in a new map.
122 /// `init` is called to obtain the initial value of each accumulator.
124 /// `operation` is a function that is invoked on each element with the following parameters:
125 /// - the current value of the accumulator of the group;
126 /// - a reference to the key of the group this element belongs to;
127 /// - the element from the source being accumulated.
129 /// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
132 /// use itertools::Itertools;
134 /// #[derive(Debug, Default)]
135 /// struct Accumulator {
139 /// let lookup = (1..=7)
140 /// .into_grouping_map_by(|&n| n % 3)
141 /// .fold_with(|_key, _val| Default::default(), |Accumulator { acc }, _key, val| {
142 /// let acc = acc + val;
143 /// Accumulator { acc }
146 /// assert_eq!(lookup[&0].acc, 3 + 6);
147 /// assert_eq!(lookup[&1].acc, 1 + 4 + 7);
148 /// assert_eq!(lookup[&2].acc, 2 + 5);
149 /// assert_eq!(lookup.len(), 3);
151 pub fn fold_with
<FI
, FO
, R
>(self, mut init
: FI
, mut operation
: FO
) -> HashMap
<K
, R
>
153 FI
: FnMut(&K
, &V
) -> R
,
154 FO
: FnMut(R
, &K
, V
) -> R
,
156 self.aggregate(|acc
, key
, val
| {
157 let acc
= acc
.unwrap_or_else(|| init(key
, &val
));
158 Some(operation(acc
, key
, val
))
162 /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
163 /// of each group sequentially, passing the previously accumulated value, a reference to the key
164 /// and the current element as arguments, and stores the results in a new map.
166 /// `init` is the value from which will be cloned the initial value of each accumulator.
168 /// `operation` is a function that is invoked on each element with the following parameters:
169 /// - the current value of the accumulator of the group;
170 /// - a reference to the key of the group this element belongs to;
171 /// - the element from the source being accumulated.
173 /// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
176 /// use itertools::Itertools;
178 /// let lookup = (1..=7)
179 /// .into_grouping_map_by(|&n| n % 3)
180 /// .fold(0, |acc, _key, val| acc + val);
182 /// assert_eq!(lookup[&0], 3 + 6);
183 /// assert_eq!(lookup[&1], 1 + 4 + 7);
184 /// assert_eq!(lookup[&2], 2 + 5);
185 /// assert_eq!(lookup.len(), 3);
187 pub fn fold
<FO
, R
>(self, init
: R
, operation
: FO
) -> HashMap
<K
, R
>
190 FO
: FnMut(R
, &K
, V
) -> R
,
192 self.fold_with(|_
, _
| init
.clone(), operation
)
195 /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
196 /// of each group sequentially, passing the previously accumulated value, a reference to the key
197 /// and the current element as arguments, and stores the results in a new map.
199 /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
201 /// `operation` is a function that is invoked on each element with the following parameters:
202 /// - the current value of the accumulator of the group;
203 /// - a reference to the key of the group this element belongs to;
204 /// - the element from the source being accumulated.
206 /// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
208 /// [`fold`]: GroupingMap::fold
211 /// use itertools::Itertools;
213 /// let lookup = (1..=7)
214 /// .into_grouping_map_by(|&n| n % 3)
215 /// .fold_first(|acc, _key, val| acc + val);
217 /// assert_eq!(lookup[&0], 3 + 6);
218 /// assert_eq!(lookup[&1], 1 + 4 + 7);
219 /// assert_eq!(lookup[&2], 2 + 5);
220 /// assert_eq!(lookup.len(), 3);
222 pub fn fold_first
<FO
>(self, mut operation
: FO
) -> HashMap
<K
, V
>
224 FO
: FnMut(V
, &K
, V
) -> V
,
226 self.aggregate(|acc
, key
, val
| {
228 Some(acc
) => operation(acc
, key
, val
),
234 /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
235 /// an instance of `C`. The iteration order is preserved when inserting elements.
237 /// Return a `HashMap` associating the key of each group with the collection containing that group's elements.
240 /// use itertools::Itertools;
241 /// use std::collections::HashSet;
243 /// let lookup = vec![0, 1, 2, 3, 4, 5, 6, 2, 3, 6].into_iter()
244 /// .into_grouping_map_by(|&n| n % 3)
245 /// .collect::<HashSet<_>>();
247 /// assert_eq!(lookup[&0], vec![0, 3, 6].into_iter().collect::<HashSet<_>>());
248 /// assert_eq!(lookup[&1], vec![1, 4].into_iter().collect::<HashSet<_>>());
249 /// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::<HashSet<_>>());
250 /// assert_eq!(lookup.len(), 3);
252 pub fn collect
<C
>(self) -> HashMap
<K
, C
>
254 C
: Default
+ Extend
<V
>,
256 let mut destination_map
= HashMap
::new();
258 self.iter
.for_each(|(key
, val
)| {
261 .or_insert_with(C
::default)
268 /// Groups elements from the `GroupingMap` source by key and finds the maximum of each group.
270 /// If several elements are equally maximum, the last element is picked.
272 /// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
275 /// use itertools::Itertools;
277 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
278 /// .into_grouping_map_by(|&n| n % 3)
281 /// assert_eq!(lookup[&0], 12);
282 /// assert_eq!(lookup[&1], 7);
283 /// assert_eq!(lookup[&2], 8);
284 /// assert_eq!(lookup.len(), 3);
286 pub fn max(self) -> HashMap
<K
, V
>
290 self.max_by(|_
, v1
, v2
| V
::cmp(v1
, v2
))
293 /// Groups elements from the `GroupingMap` source by key and finds the maximum of each group
294 /// with respect to the specified comparison function.
296 /// If several elements are equally maximum, the last element is picked.
298 /// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
301 /// use itertools::Itertools;
303 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
304 /// .into_grouping_map_by(|&n| n % 3)
305 /// .max_by(|_key, x, y| y.cmp(x));
307 /// assert_eq!(lookup[&0], 3);
308 /// assert_eq!(lookup[&1], 1);
309 /// assert_eq!(lookup[&2], 5);
310 /// assert_eq!(lookup.len(), 3);
312 pub fn max_by
<F
>(self, mut compare
: F
) -> HashMap
<K
, V
>
314 F
: FnMut(&K
, &V
, &V
) -> Ordering
,
316 self.fold_first(|acc
, key
, val
| match compare(key
, &acc
, &val
) {
317 Ordering
::Less
| Ordering
::Equal
=> val
,
318 Ordering
::Greater
=> acc
,
322 /// Groups elements from the `GroupingMap` source by key and finds the element of each group
323 /// that gives the maximum from the specified function.
325 /// If several elements are equally maximum, the last element is picked.
327 /// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
330 /// use itertools::Itertools;
332 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
333 /// .into_grouping_map_by(|&n| n % 3)
334 /// .max_by_key(|_key, &val| val % 4);
336 /// assert_eq!(lookup[&0], 3);
337 /// assert_eq!(lookup[&1], 7);
338 /// assert_eq!(lookup[&2], 5);
339 /// assert_eq!(lookup.len(), 3);
341 pub fn max_by_key
<F
, CK
>(self, mut f
: F
) -> HashMap
<K
, V
>
343 F
: FnMut(&K
, &V
) -> CK
,
346 self.max_by(|key
, v1
, v2
| f(key
, v1
).cmp(&f(key
, v2
)))
349 /// Groups elements from the `GroupingMap` source by key and finds the minimum of each group.
351 /// If several elements are equally minimum, the first element is picked.
353 /// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
356 /// use itertools::Itertools;
358 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
359 /// .into_grouping_map_by(|&n| n % 3)
362 /// assert_eq!(lookup[&0], 3);
363 /// assert_eq!(lookup[&1], 1);
364 /// assert_eq!(lookup[&2], 5);
365 /// assert_eq!(lookup.len(), 3);
367 pub fn min(self) -> HashMap
<K
, V
>
371 self.min_by(|_
, v1
, v2
| V
::cmp(v1
, v2
))
374 /// Groups elements from the `GroupingMap` source by key and finds the minimum of each group
375 /// with respect to the specified comparison function.
377 /// If several elements are equally minimum, the first element is picked.
379 /// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
382 /// use itertools::Itertools;
384 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
385 /// .into_grouping_map_by(|&n| n % 3)
386 /// .min_by(|_key, x, y| y.cmp(x));
388 /// assert_eq!(lookup[&0], 12);
389 /// assert_eq!(lookup[&1], 7);
390 /// assert_eq!(lookup[&2], 8);
391 /// assert_eq!(lookup.len(), 3);
393 pub fn min_by
<F
>(self, mut compare
: F
) -> HashMap
<K
, V
>
395 F
: FnMut(&K
, &V
, &V
) -> Ordering
,
397 self.fold_first(|acc
, key
, val
| match compare(key
, &acc
, &val
) {
398 Ordering
::Less
| Ordering
::Equal
=> acc
,
399 Ordering
::Greater
=> val
,
403 /// Groups elements from the `GroupingMap` source by key and finds the element of each group
404 /// that gives the minimum from the specified function.
406 /// If several elements are equally minimum, the first element is picked.
408 /// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
411 /// use itertools::Itertools;
413 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
414 /// .into_grouping_map_by(|&n| n % 3)
415 /// .min_by_key(|_key, &val| val % 4);
417 /// assert_eq!(lookup[&0], 12);
418 /// assert_eq!(lookup[&1], 4);
419 /// assert_eq!(lookup[&2], 8);
420 /// assert_eq!(lookup.len(), 3);
422 pub fn min_by_key
<F
, CK
>(self, mut f
: F
) -> HashMap
<K
, V
>
424 F
: FnMut(&K
, &V
) -> CK
,
427 self.min_by(|key
, v1
, v2
| f(key
, v1
).cmp(&f(key
, v2
)))
430 /// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
433 /// If several elements are equally maximum, the last element is picked.
434 /// If several elements are equally minimum, the first element is picked.
436 /// See [.minmax()](crate::Itertools::minmax) for the non-grouping version.
438 /// Differences from the non grouping version:
439 /// - It never produces a `MinMaxResult::NoElements`
440 /// - It doesn't have any speedup
442 /// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
445 /// use itertools::Itertools;
446 /// use itertools::MinMaxResult::{OneElement, MinMax};
448 /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
449 /// .into_grouping_map_by(|&n| n % 3)
452 /// assert_eq!(lookup[&0], MinMax(3, 12));
453 /// assert_eq!(lookup[&1], MinMax(1, 7));
454 /// assert_eq!(lookup[&2], OneElement(5));
455 /// assert_eq!(lookup.len(), 3);
457 pub fn minmax(self) -> HashMap
<K
, MinMaxResult
<V
>>
461 self.minmax_by(|_
, v1
, v2
| V
::cmp(v1
, v2
))
464 /// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
465 /// each group with respect to the specified comparison function.
467 /// If several elements are equally maximum, the last element is picked.
468 /// If several elements are equally minimum, the first element is picked.
470 /// It has the same differences from the non-grouping version as `minmax`.
472 /// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
475 /// use itertools::Itertools;
476 /// use itertools::MinMaxResult::{OneElement, MinMax};
478 /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
479 /// .into_grouping_map_by(|&n| n % 3)
480 /// .minmax_by(|_key, x, y| y.cmp(x));
482 /// assert_eq!(lookup[&0], MinMax(12, 3));
483 /// assert_eq!(lookup[&1], MinMax(7, 1));
484 /// assert_eq!(lookup[&2], OneElement(5));
485 /// assert_eq!(lookup.len(), 3);
487 pub fn minmax_by
<F
>(self, mut compare
: F
) -> HashMap
<K
, MinMaxResult
<V
>>
489 F
: FnMut(&K
, &V
, &V
) -> Ordering
,
491 self.aggregate(|acc
, key
, val
| {
493 Some(MinMaxResult
::OneElement(e
)) => {
494 if compare(key
, &val
, &e
) == Ordering
::Less
{
495 MinMaxResult
::MinMax(val
, e
)
497 MinMaxResult
::MinMax(e
, val
)
500 Some(MinMaxResult
::MinMax(min
, max
)) => {
501 if compare(key
, &val
, &min
) == Ordering
::Less
{
502 MinMaxResult
::MinMax(val
, max
)
503 } else if compare(key
, &val
, &max
) != Ordering
::Less
{
504 MinMaxResult
::MinMax(min
, val
)
506 MinMaxResult
::MinMax(min
, max
)
509 None
=> MinMaxResult
::OneElement(val
),
510 Some(MinMaxResult
::NoElements
) => unreachable
!(),
515 /// Groups elements from the `GroupingMap` source by key and find the elements of each group
516 /// that gives the minimum and maximum from the specified function.
518 /// If several elements are equally maximum, the last element is picked.
519 /// If several elements are equally minimum, the first element is picked.
521 /// It has the same differences from the non-grouping version as `minmax`.
523 /// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
526 /// use itertools::Itertools;
527 /// use itertools::MinMaxResult::{OneElement, MinMax};
529 /// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
530 /// .into_grouping_map_by(|&n| n % 3)
531 /// .minmax_by_key(|_key, &val| val % 4);
533 /// assert_eq!(lookup[&0], MinMax(12, 3));
534 /// assert_eq!(lookup[&1], MinMax(4, 7));
535 /// assert_eq!(lookup[&2], OneElement(5));
536 /// assert_eq!(lookup.len(), 3);
538 pub fn minmax_by_key
<F
, CK
>(self, mut f
: F
) -> HashMap
<K
, MinMaxResult
<V
>>
540 F
: FnMut(&K
, &V
) -> CK
,
543 self.minmax_by(|key
, v1
, v2
| f(key
, v1
).cmp(&f(key
, v2
)))
546 /// Groups elements from the `GroupingMap` source by key and sums them.
548 /// This is just a shorthand for `self.fold_first(|acc, _, val| acc + val)`.
549 /// It is more limited than `Iterator::sum` since it doesn't use the `Sum` trait.
551 /// Returns a `HashMap` associating the key of each group with the sum of that group's elements.
554 /// use itertools::Itertools;
556 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
557 /// .into_grouping_map_by(|&n| n % 3)
560 /// assert_eq!(lookup[&0], 3 + 9 + 12);
561 /// assert_eq!(lookup[&1], 1 + 4 + 7);
562 /// assert_eq!(lookup[&2], 5 + 8);
563 /// assert_eq!(lookup.len(), 3);
565 pub fn sum(self) -> HashMap
<K
, V
>
567 V
: Add
<V
, Output
= V
>,
569 self.fold_first(|acc
, _
, val
| acc
+ val
)
572 /// Groups elements from the `GroupingMap` source by key and multiply them.
574 /// This is just a shorthand for `self.fold_first(|acc, _, val| acc * val)`.
575 /// It is more limited than `Iterator::product` since it doesn't use the `Product` trait.
577 /// Returns a `HashMap` associating the key of each group with the product of that group's elements.
580 /// use itertools::Itertools;
582 /// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
583 /// .into_grouping_map_by(|&n| n % 3)
586 /// assert_eq!(lookup[&0], 3 * 9 * 12);
587 /// assert_eq!(lookup[&1], 1 * 4 * 7);
588 /// assert_eq!(lookup[&2], 5 * 8);
589 /// assert_eq!(lookup.len(), 3);
591 pub fn product(self) -> HashMap
<K
, V
>
593 V
: Mul
<V
, Output
= V
>,
595 self.fold_first(|acc
, _
, val
| acc
* val
)