use crate::collection::Collection;
use std::collections::HashMap;
pub fn group_by<T, K, F>(collection: &[T], iteratee: F) -> HashMap<K, Vec<T>>
where
K: std::hash::Hash + Eq,
T: Clone,
F: Fn(&T) -> K,
{
let mut groups = HashMap::new();
for item in collection {
let key = iteratee(item);
groups.entry(key).or_insert_with(Vec::new).push(item.clone());
}
groups
}
pub fn key_by<T, K, F>(collection: &[T], iteratee: F) -> HashMap<K, T>
where
K: std::hash::Hash + Eq,
T: Clone,
F: Fn(&T) -> K,
{
let mut keyed = HashMap::new();
for item in collection {
let key = iteratee(item);
keyed.insert(key, item.clone());
}
keyed
}
pub fn invoke<T, U, F>(collection: &[T], method: F) -> Vec<U>
where
F: Fn(&T) -> U,
{
collection.iter().map(method).collect()
}
pub fn sort_by<T, K, F>(collection: &[T], iteratee: F) -> Vec<T>
where
T: Clone,
K: Ord,
F: Fn(&T) -> K,
{
let mut sorted = collection.to_vec();
sorted.sort_by_key(iteratee);
sorted
}
pub fn order_by<T, K, F>(collection: &[T], iteratee: F, ascending: bool) -> Vec<T>
where
T: Clone,
K: Ord,
F: Fn(&T) -> K,
{
let mut sorted = collection.to_vec();
if ascending {
sorted.sort_by_key(iteratee);
} else {
sorted.sort_by(|a, b| {
let key_a = iteratee(a);
let key_b = iteratee(b);
key_b.cmp(&key_a)
});
}
sorted
}
impl<T> Collection<T> {
pub fn group_by<K, F>(&self, iteratee: F) -> HashMap<K, Vec<T>>
where
K: std::hash::Hash + Eq,
T: Clone,
F: Fn(&T) -> K,
{
group_by(&self.data, iteratee)
}
pub fn key_by<K, F>(&self, iteratee: F) -> HashMap<K, T>
where
K: std::hash::Hash + Eq,
T: Clone,
F: Fn(&T) -> K,
{
key_by(&self.data, iteratee)
}
pub fn invoke<U, F>(&self, method: F) -> Vec<U>
where
F: Fn(&T) -> U,
{
invoke(&self.data, method)
}
pub fn sort_by<K, F>(&self, iteratee: F) -> Vec<T>
where
T: Clone,
K: Ord,
F: Fn(&T) -> K,
{
sort_by(&self.data, iteratee)
}
pub fn order_by<K, F>(&self, iteratee: F, ascending: bool) -> Vec<T>
where
T: Clone,
K: Ord,
F: Fn(&T) -> K,
{
order_by(&self.data, iteratee, ascending)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_group_by() {
let numbers = vec![6.1, 4.2, 6.3];
let grouped = group_by(&numbers, |x| {
#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)]
{
(*x as f64).floor() as i32
}
});
assert_eq!(grouped.get(&6), Some(&vec![6.1, 6.3]));
assert_eq!(grouped.get(&4), Some(&vec![4.2]));
}
#[test]
fn test_key_by() {
let users = vec![
("john", 30),
("jane", 25),
("bob", 35),
];
let keyed = key_by(&users, |(name, _)| (*name).to_string());
assert_eq!(keyed.get("john"), Some(&("john", 30)));
assert_eq!(keyed.get("jane"), Some(&("jane", 25)));
assert_eq!(keyed.get("bob"), Some(&("bob", 35)));
}
#[test]
fn test_invoke() {
let strings = vec!["hello", "world"];
let uppercased = invoke(&strings, |s| s.to_uppercase());
assert_eq!(uppercased, vec!["HELLO", "WORLD"]);
}
#[test]
fn test_sort_by() {
let users = vec![
("john", 30),
("jane", 25),
("bob", 35),
];
let sorted = sort_by(&users, |(_, age)| *age);
assert_eq!(sorted[0], ("jane", 25));
assert_eq!(sorted[1], ("john", 30));
assert_eq!(sorted[2], ("bob", 35));
}
#[test]
fn test_order_by_ascending() {
let users = vec![
("john", 30),
("jane", 25),
("bob", 35),
];
let sorted = order_by(&users, |(_, age)| *age, true);
assert_eq!(sorted[0], ("jane", 25));
assert_eq!(sorted[1], ("john", 30));
assert_eq!(sorted[2], ("bob", 35));
}
#[test]
fn test_order_by_descending() {
let users = vec![
("john", 30),
("jane", 25),
("bob", 35),
];
let sorted = order_by(&users, |(_, age)| *age, false);
assert_eq!(sorted[0], ("bob", 35));
assert_eq!(sorted[1], ("john", 30));
assert_eq!(sorted[2], ("jane", 25));
}
#[test]
fn test_collection_group_by() {
let collection = Collection::new(vec![6.1, 4.2, 6.3]);
let grouped = collection.group_by(|x| {
#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)]
{
(*x as f64).floor() as i32
}
});
assert_eq!(grouped.get(&6), Some(&vec![6.1, 6.3]));
}
#[test]
fn test_collection_key_by() {
let collection = Collection::new(vec![
("john", 30),
("jane", 25),
("bob", 35),
]);
let keyed = collection.key_by(|(name, _)| (*name).to_string());
assert_eq!(keyed.get("john"), Some(&("john", 30)));
}
#[test]
fn test_collection_invoke() {
let collection = Collection::new(vec!["hello", "world"]);
let uppercased = collection.invoke(|s| s.to_uppercase());
assert_eq!(uppercased, vec!["HELLO", "WORLD"]);
}
#[test]
fn test_collection_sort_by() {
let collection = Collection::new(vec![
("john", 30),
("jane", 25),
("bob", 35),
]);
let sorted = collection.sort_by(|(_, age)| *age);
assert_eq!(sorted[0], ("jane", 25));
}
#[test]
fn test_collection_order_by() {
let collection = Collection::new(vec![
("john", 30),
("jane", 25),
("bob", 35),
]);
let sorted = collection.order_by(|(_, age)| *age, false);
assert_eq!(sorted[0], ("bob", 35));
}
#[test]
fn test_empty_collection() {
let empty: Vec<i32> = vec![];
let grouped = group_by(&empty, |x| x % 2);
assert!(grouped.is_empty());
let keyed = key_by(&empty, std::string::ToString::to_string);
assert!(keyed.is_empty());
let invoked = invoke(&empty, |x| x * 2);
assert!(invoked.is_empty());
let sorted = sort_by(&empty, |x| *x);
assert!(sorted.is_empty());
}
}