use std::collections::HashMap;
use std::hash::Hash;
pub trait EloquentCollection<T> {
fn key_by<K, F>(self, f: F) -> HashMap<K, T>
where
F: Fn(&T) -> K,
K: Hash + Eq;
fn chunk(self, size: usize) -> Vec<Vec<T>>;
fn implode<F>(&self, separator: &str, f: F) -> String
where
F: Fn(&T) -> String;
fn sum_by<N, F>(&self, f: F) -> N
where
F: Fn(&T) -> N,
N: std::iter::Sum;
fn max_by_key<K, F>(&self, f: F) -> Option<&T>
where
F: Fn(&T) -> K,
K: Ord;
fn min_by_key<K, F>(&self, f: F) -> Option<&T>
where
F: Fn(&T) -> K,
K: Ord;
}
impl<T> EloquentCollection<T> for Vec<T> {
fn key_by<K, F>(self, f: F) -> HashMap<K, T>
where
F: Fn(&T) -> K,
K: Hash + Eq,
{
let mut map = HashMap::with_capacity(self.len());
for item in self {
map.insert(f(&item), item);
}
map
}
fn chunk(self, size: usize) -> Vec<Vec<T>> {
if size == 0 {
return vec![self];
}
let mut chunks = Vec::with_capacity(self.len().div_ceil(size));
let mut current_chunk = Vec::with_capacity(size);
for item in self {
current_chunk.push(item);
if current_chunk.len() == size {
chunks.push(current_chunk);
current_chunk = Vec::with_capacity(size);
}
}
if !current_chunk.is_empty() {
chunks.push(current_chunk);
}
chunks
}
fn implode<F>(&self, separator: &str, f: F) -> String
where
F: Fn(&T) -> String,
{
let mut result = String::new();
let mut iter = self.iter();
if let Some(first) = iter.next() {
result.push_str(&f(first));
for item in iter {
result.push_str(separator);
result.push_str(&f(item));
}
}
result
}
fn sum_by<N, F>(&self, f: F) -> N
where
F: Fn(&T) -> N,
N: std::iter::Sum,
{
self.iter().map(f).sum()
}
fn max_by_key<K, F>(&self, f: F) -> Option<&T>
where
F: Fn(&T) -> K,
K: Ord,
{
self.iter().max_by_key(|item| f(*item))
}
fn min_by_key<K, F>(&self, f: F) -> Option<&T>
where
F: Fn(&T) -> K,
K: Ord,
{
self.iter().min_by_key(|item| f(*item))
}
}