use super::super::orderedmap::*;
pub trait GroupByExtension: IntoIterator {
fn group_by<K>(self, f: impl Fn(&Self::Item) -> K) -> IntoIter<K, Self::Item>
where
K: Eq + std::hash::Hash + Clone,
Self: Sized,
{
let mut map = OrderedVecMap::new();
for item in self {
let key = f(&item);
map.insert_push(key, item);
}
map.into_iter()
}
fn group_by_with<K, V>(
self,
f: impl Fn(&Self::Item) -> K,
vf: impl Fn(&Self::Item) -> V,
) -> IntoIter<K, V>
where
K: Eq + std::hash::Hash + Clone,
Self: Sized,
{
let mut map = OrderedVecMap::new();
for item in self {
let key = f(&item);
map.insert_push(key, vf(&item));
}
map.into_iter()
}
}
impl<I> GroupByExtension for I where I: IntoIterator {}
#[cfg(test)]
mod tests {
use crate::prelude::ToCollectionIteratorExtension;
use super::*;
#[test]
fn can_groupby_array() {
let vec = [1, 1, 2, 3, 3, 1];
let map = vec.group_by(|a| *a).to_hashmap();
assert_eq!(map.len(), 3);
assert_eq!(map.get(&1).unwrap(), &vec![1, 1, 1]);
assert_eq!(map.get(&2).unwrap(), &vec![2]);
assert_eq!(map.get(&3).unwrap(), &vec![3, 3]);
}
#[test]
fn group_by_iter() {
let vec = [1, 1, 2, 3, 3, 1];
let map = vec.group_by(|a| *a);
assert_eq!(map.count(), 3);
let mut map = vec.group_by(|a| *a);
assert!(map.next().is_some());
assert!(map.next().is_some());
assert!(map.next().is_some());
assert!(map.next().is_none());
}
#[test]
fn can_group_by_vec_strings() {
let vec = ["1", "1", "22", "333", "333", "1"];
let map = vec.group_by(|a| a.len()).to_hashmap();
assert_eq!(map.len(), 3);
assert_eq!(map.get(&1).unwrap(), &["1", "1", "1"]);
assert_eq!(map.get(&2).unwrap(), &["22"]);
assert_eq!(map.get(&3).unwrap(), &["333", "333"]);
}
#[test]
fn group_by_struct() {
struct Person {
name: String,
age: u8,
}
let persons = vec![
Person {
name: "Alice".to_string(),
age: 20,
},
Person {
name: "Bob".to_string(),
age: 20,
},
Person {
name: "Charlie".to_string(),
age: 30,
},
Person {
name: "Danny".to_string(),
age: 20,
},
];
let map = persons.iter().group_by(|a| a.age).to_hashmap();
assert_eq!(map.len(), 2);
assert_eq!(map.get(&20).unwrap().len(), 3);
assert_eq!(map.get(&30).unwrap().len(), 1);
assert_eq!(map.get(&30).unwrap().first().unwrap().name, "Charlie");
let map = persons.group_by(|a| a.name.len());
assert_eq!(map.count(), 3);
}
#[test]
fn group_by_with() {
struct Person {
name: String,
age: u8,
}
let persons = vec![
Person {
name: "Alice".to_string(),
age: 20,
},
Person {
name: "Bob".to_string(),
age: 20,
},
Person {
name: "Charlie".to_string(),
age: 30,
},
];
let map = persons
.iter()
.group_by_with(|a| a.age, |a| a.name.clone())
.to_hashmap();
assert_eq!(map.len(), 2);
assert_eq!(map.get(&20).unwrap().len(), 2);
assert_eq!(map.get(&30).unwrap().len(), 1);
assert_eq!(map.get(&30).unwrap().first().unwrap(), &"Charlie");
let mut map = persons.group_by_with(|a| a.age, |a| a.name.len());
assert!(map.next().is_some());
assert!(map.next().is_some());
assert!(map.next().is_none());
}
#[test]
fn ordering() {
let vec = [2, 1, 1, 3, 3, 1];
let mut map = vec.group_by(|a| *a);
assert_eq!(map.next(), Some((2, vec![2])));
assert_eq!(map.next(), Some((1, vec![1, 1, 1])));
assert_eq!(map.next(), Some((3, vec![3, 3])));
}
}