From 3db9c7e6a0bf583ebe1cefcc71aa496b7ebeffbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Brandst=C3=B6tter?= Date: Mon, 23 Dec 2024 13:08:21 +0100 Subject: [PATCH] Add `into_grouping_map_[by_]with_hasher` --- src/grouping_map.rs | 57 +++++++++++++++++++++++++-------------------- src/lib.rs | 43 ++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/grouping_map.rs b/src/grouping_map.rs index 86cb55dc0..d8e435c4c 100644 --- a/src/grouping_map.rs +++ b/src/grouping_map.rs @@ -2,11 +2,12 @@ use crate::{ adaptors::map::{MapSpecialCase, MapSpecialCaseFn}, MinMaxResult, }; -use std::cmp::Ordering; +use core::hash::BuildHasher; use std::collections::HashMap; use std::hash::Hash; use std::iter::Iterator; use std::ops::{Add, Mul}; +use std::{cmp::Ordering, hash::RandomState}; /// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by) pub type MapForGrouping = MapSpecialCase>; @@ -36,18 +37,19 @@ pub(crate) fn new_map_for_grouping K>( } /// Creates a new `GroupingMap` from `iter` -pub fn new(iter: I) -> GroupingMap +pub fn new(iter: I, hash_builder: S) -> GroupingMap where I: Iterator, K: Hash + Eq, + S: BuildHasher, { - GroupingMap { iter } + GroupingMap { iter, hash_builder } } /// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations. /// /// See [`GroupingMap`] for more informations. -pub type GroupingMapBy = GroupingMap>; +pub type GroupingMapBy = GroupingMap, S>; /// `GroupingMap` is an intermediate struct for efficient group-and-fold operations. /// It groups elements by their key and at the same time fold each group @@ -56,14 +58,19 @@ pub type GroupingMapBy = GroupingMap>; /// No method on this struct performs temporary allocations. #[derive(Clone, Debug)] #[must_use = "GroupingMap is lazy and do nothing unless consumed"] -pub struct GroupingMap { +pub struct GroupingMap +where + S: BuildHasher, +{ iter: I, + hash_builder: S, } -impl GroupingMap +impl GroupingMap where I: Iterator, K: Hash + Eq, + S: BuildHasher, { /// This is the generic way to perform any operation on a `GroupingMap`. /// It's suggested to use this method only to implement custom operations @@ -105,11 +112,11 @@ where /// assert_eq!(lookup[&3], 7); /// assert_eq!(lookup.len(), 3); // The final keys are only 0, 1 and 2 /// ``` - pub fn aggregate(self, mut operation: FO) -> HashMap + pub fn aggregate(self, mut operation: FO) -> HashMap where FO: FnMut(Option, &K, V) -> Option, { - let mut destination_map = HashMap::new(); + let mut destination_map = HashMap::with_hasher(self.hash_builder); self.iter.for_each(|(key, val)| { let acc = destination_map.remove(&key); @@ -154,7 +161,7 @@ where /// assert_eq!(lookup[&2].acc, 2 + 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn fold_with(self, mut init: FI, mut operation: FO) -> HashMap + pub fn fold_with(self, mut init: FI, mut operation: FO) -> HashMap where FI: FnMut(&K, &V) -> R, FO: FnMut(R, &K, V) -> R, @@ -190,7 +197,7 @@ where /// assert_eq!(lookup[&2], 2 + 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn fold(self, init: R, operation: FO) -> HashMap + pub fn fold(self, init: R, operation: FO) -> HashMap where R: Clone, FO: FnMut(R, &K, V) -> R, @@ -225,7 +232,7 @@ where /// assert_eq!(lookup[&2], 2 + 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn reduce(self, mut operation: FO) -> HashMap + pub fn reduce(self, mut operation: FO) -> HashMap where FO: FnMut(V, &K, V) -> V, { @@ -239,7 +246,7 @@ where /// See [`.reduce()`](GroupingMap::reduce). #[deprecated(note = "Use .reduce() instead", since = "0.13.0")] - pub fn fold_first(self, operation: FO) -> HashMap + pub fn fold_first(self, operation: FO) -> HashMap where FO: FnMut(V, &K, V) -> V, { @@ -264,11 +271,11 @@ where /// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::>()); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn collect(self) -> HashMap + pub fn collect(self) -> HashMap where C: Default + Extend, { - let mut destination_map = HashMap::new(); + let mut destination_map = HashMap::with_hasher(self.hash_builder); self.iter.for_each(|(key, val)| { destination_map @@ -298,7 +305,7 @@ where /// assert_eq!(lookup[&2], 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn max(self) -> HashMap + pub fn max(self) -> HashMap where V: Ord, { @@ -324,7 +331,7 @@ where /// assert_eq!(lookup[&2], 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn max_by(self, mut compare: F) -> HashMap + pub fn max_by(self, mut compare: F) -> HashMap where F: FnMut(&K, &V, &V) -> Ordering, { @@ -353,7 +360,7 @@ where /// assert_eq!(lookup[&2], 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn max_by_key(self, mut f: F) -> HashMap + pub fn max_by_key(self, mut f: F) -> HashMap where F: FnMut(&K, &V) -> CK, CK: Ord, @@ -379,7 +386,7 @@ where /// assert_eq!(lookup[&2], 5); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn min(self) -> HashMap + pub fn min(self) -> HashMap where V: Ord, { @@ -405,7 +412,7 @@ where /// assert_eq!(lookup[&2], 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn min_by(self, mut compare: F) -> HashMap + pub fn min_by(self, mut compare: F) -> HashMap where F: FnMut(&K, &V, &V) -> Ordering, { @@ -434,7 +441,7 @@ where /// assert_eq!(lookup[&2], 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn min_by_key(self, mut f: F) -> HashMap + pub fn min_by_key(self, mut f: F) -> HashMap where F: FnMut(&K, &V) -> CK, CK: Ord, @@ -469,7 +476,7 @@ where /// assert_eq!(lookup[&2], OneElement(5)); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn minmax(self) -> HashMap> + pub fn minmax(self) -> HashMap, S> where V: Ord, { @@ -499,7 +506,7 @@ where /// assert_eq!(lookup[&2], OneElement(5)); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn minmax_by(self, mut compare: F) -> HashMap> + pub fn minmax_by(self, mut compare: F) -> HashMap, S> where F: FnMut(&K, &V, &V) -> Ordering, { @@ -550,7 +557,7 @@ where /// assert_eq!(lookup[&2], OneElement(5)); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn minmax_by_key(self, mut f: F) -> HashMap> + pub fn minmax_by_key(self, mut f: F) -> HashMap, S> where F: FnMut(&K, &V) -> CK, CK: Ord, @@ -577,7 +584,7 @@ where /// assert_eq!(lookup[&2], 5 + 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn sum(self) -> HashMap + pub fn sum(self) -> HashMap where V: Add, { @@ -603,7 +610,7 @@ where /// assert_eq!(lookup[&2], 5 * 8); /// assert_eq!(lookup.len(), 3); /// ``` - pub fn product(self) -> HashMap + pub fn product(self) -> HashMap where V: Mul, { diff --git a/src/lib.rs b/src/lib.rs index 732fbf25f..f2f580eb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3921,7 +3921,21 @@ pub trait Itertools: Iterator { Self: Iterator + Sized, K: Hash + Eq, { - grouping_map::new(self) + grouping_map::new(self, RandomState::new()) + } + + /// Constructs a `GroupingMap` to be used later with one of the efficient + /// group-and-fold operations it allows to perform, using the specified hash builder for + /// hashing the elements. + /// See [.into_grouping_map()](crate::Itertools::into_grouping_map) for more information. + #[cfg(feature = "use_std")] + fn into_grouping_map_with_hasher(self, hash_builder: S) -> GroupingMap + where + Self: Iterator + Sized, + K: Hash + Eq, + S: BuildHasher, + { + grouping_map::new(self, hash_builder) } /// Constructs a `GroupingMap` to be used later with one of the efficient @@ -3939,7 +3953,32 @@ pub trait Itertools: Iterator { K: Hash + Eq, F: FnMut(&V) -> K, { - grouping_map::new(grouping_map::new_map_for_grouping(self, key_mapper)) + grouping_map::new( + grouping_map::new_map_for_grouping(self, key_mapper), + RandomState::new(), + ) + } + + /// Constructs a `GroupingMap` to be used later with one of the efficient + /// group-and-fold operations it allows to perform, using the specified hash builder for + /// hashing the keys. + /// See [.into_grouping_map_by()](crate::Itertools::into_grouping_map_by) for more information. + #[cfg(feature = "use_std")] + fn into_grouping_map_by_with_hasher( + self, + key_mapper: F, + hash_builder: S, + ) -> GroupingMapBy + where + Self: Iterator + Sized, + K: Hash + Eq, + F: FnMut(&V) -> K, + S: BuildHasher, + { + grouping_map::new( + grouping_map::new_map_for_grouping(self, key_mapper), + hash_builder, + ) } /// Return all minimum elements of an iterator.