Skip to content

Commit 4324c14

Browse files
committed
Add into_group_map_[by_]with_hasher
1 parent 356362c commit 4324c14

File tree

2 files changed

+87
-6
lines changed

2 files changed

+87
-6
lines changed

src/group_map.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![cfg(feature = "use_std")]
22

3+
use core::hash::BuildHasher;
34
use std::collections::HashMap;
45
use std::hash::Hash;
56
use std::iter::Iterator;
@@ -8,12 +9,13 @@ use std::iter::Iterator;
89
///
910
/// See [`.into_group_map()`](crate::Itertools::into_group_map)
1011
/// for more information.
11-
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
12+
pub fn into_group_map_with_hasher<I, K, V, S>(iter: I, hash_builder: S) -> HashMap<K, Vec<V>, S>
1213
where
1314
I: Iterator<Item = (K, V)>,
1415
K: Hash + Eq,
16+
S: BuildHasher,
1517
{
16-
let mut lookup = HashMap::new();
18+
let mut lookup = HashMap::with_hasher(hash_builder);
1719

1820
iter.for_each(|(key, val)| {
1921
lookup.entry(key).or_insert_with(Vec::new).push(val);
@@ -22,11 +24,16 @@ where
2224
lookup
2325
}
2426

25-
pub fn into_group_map_by<I, K, V, F>(iter: I, mut f: F) -> HashMap<K, Vec<V>>
27+
pub fn into_group_map_by_with_hasher<I, K, V, F, S>(
28+
iter: I,
29+
mut f: F,
30+
hash_builder: S,
31+
) -> HashMap<K, Vec<V>, S>
2632
where
2733
I: Iterator<Item = V>,
2834
K: Hash + Eq,
2935
F: FnMut(&V) -> K,
36+
S: BuildHasher,
3037
{
31-
into_group_map(iter.map(|v| (f(&v), v)))
38+
into_group_map_with_hasher(iter.map(|v| (f(&v), v)), hash_builder)
3239
}

src/lib.rs

+76-2
Original file line numberDiff line numberDiff line change
@@ -3792,7 +3792,36 @@ pub trait Itertools: Iterator {
37923792
Self: Iterator<Item = (K, V)> + Sized,
37933793
K: Hash + Eq,
37943794
{
3795-
group_map::into_group_map(self)
3795+
group_map::into_group_map_with_hasher(self, RandomState::new())
3796+
}
3797+
3798+
/// Return a `HashMap` of keys mapped to `Vec`s of values, using the hash builder for hashing.
3799+
/// See [.into_group_map()](crate::Itertools::into_group_map) for more information.
3800+
///
3801+
/// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's
3802+
/// users to be resistant to attacks that cause many collisions and very poor performance.
3803+
/// Setting it manually using this function can expose a DoS attack vector.
3804+
///
3805+
/// ```
3806+
/// use std::hash::RandomState;
3807+
/// use itertools::Itertools;
3808+
///
3809+
/// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)];
3810+
/// let lookup = data.into_iter().into_group_map_with_hasher(RandomState::new());
3811+
///
3812+
/// assert_eq!(lookup[&0], vec![10, 20]);
3813+
/// assert_eq!(lookup.get(&1), None);
3814+
/// assert_eq!(lookup[&2], vec![12, 42]);
3815+
/// assert_eq!(lookup[&3], vec![13, 33]);
3816+
/// ```
3817+
#[cfg(feature = "use_std")]
3818+
fn into_group_map_with_hasher<K, V, S>(self, hash_builder: S) -> HashMap<K, Vec<V>, S>
3819+
where
3820+
Self: Iterator<Item = (K, V)> + Sized,
3821+
K: Hash + Eq,
3822+
S: BuildHasher,
3823+
{
3824+
group_map::into_group_map_with_hasher(self, hash_builder)
37963825
}
37973826

37983827
/// Return a `HashMap` of keys mapped to `Vec`s of values. The key is specified
@@ -3829,7 +3858,52 @@ pub trait Itertools: Iterator {
38293858
K: Hash + Eq,
38303859
F: FnMut(&V) -> K,
38313860
{
3832-
group_map::into_group_map_by(self, f)
3861+
group_map::into_group_map_by_with_hasher(self, f, RandomState::new())
3862+
}
3863+
3864+
/// Return a `HashMap` of keys mapped to `Vec`s of values, using the hash builder for hashing.
3865+
/// See [.into_group_map_by()](crate::Itertools::into_group_map_by) for more information.
3866+
///
3867+
/// Warning: `hash_builder` is normally randomly generated, and is designed to allow it's
3868+
/// users to be resistant to attacks that cause many collisions and very poor performance.
3869+
/// Setting it manually using this function can expose a DoS attack vector.
3870+
///
3871+
/// ```
3872+
/// use itertools::Itertools;
3873+
/// use std::collections::HashMap;
3874+
/// use std::hash::RandomState;
3875+
///
3876+
/// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)];
3877+
/// let lookup: HashMap<u32,Vec<(u32, u32)>> =
3878+
/// data.clone().into_iter().into_group_map_by_with_hasher(|a| a.0, RandomState::new());
3879+
///
3880+
/// assert_eq!(lookup[&0], vec![(0,10), (0,20)]);
3881+
/// assert_eq!(lookup.get(&1), None);
3882+
/// assert_eq!(lookup[&2], vec![(2,12), (2,42)]);
3883+
/// assert_eq!(lookup[&3], vec![(3,13), (3,33)]);
3884+
///
3885+
/// assert_eq!(
3886+
/// data.into_iter()
3887+
/// .into_group_map_by_with_hasher(|x| x.0, RandomState::new())
3888+
/// .into_iter()
3889+
/// .map(|(key, values)| (key, values.into_iter().fold(0,|acc, (_,v)| acc + v )))
3890+
/// .collect::<HashMap<u32,u32>>()[&0],
3891+
/// 30,
3892+
/// );
3893+
/// ```
3894+
#[cfg(feature = "use_std")]
3895+
fn into_group_map_by_with_hasher<K, V, F, S>(
3896+
self,
3897+
f: F,
3898+
hash_builder: S,
3899+
) -> HashMap<K, Vec<V>, S>
3900+
where
3901+
Self: Iterator<Item = V> + Sized,
3902+
K: Hash + Eq,
3903+
F: FnMut(&V) -> K,
3904+
S: BuildHasher,
3905+
{
3906+
group_map::into_group_map_by_with_hasher(self, f, hash_builder)
38333907
}
38343908

38353909
/// Constructs a `GroupingMap` to be used later with one of the efficient

0 commit comments

Comments
 (0)