pub trait FluentIter: Iterator + Sized {
fn group_by_stable<K, F>(self, key: F) -> Vec<(K, Vec<Self::Item>)>
where
K: Eq + Hash + Clone,
F: FnMut(&Self::Item) -> K,
{
let mut key = key;
let mut index: HashMap<K, usize> = HashMap::new();
let mut out: Vec<(K, Vec<Self::Item>)> = Vec::new();
for item in self {
let k = key(&item);
match index.get(&k) {
Some(&i) => out[i].1.push(item),
None => {
index.insert(k.clone(), out.len());
out.push((k, vec![item]));
}
}
}
out
}
fn to_map_by<K, V>(
self,
mut key: impl FnMut(&Self::Item) -> K,
mut value: impl FnMut(&Self::Item) -> V,
) -> HashMap<K, V>
where
K: Eq + Hash,
{
self.map(|item| (key(&item), value(&item))).collect()
}
fn to_map_chain<K1, K2>(
self,
mut key1: impl FnMut(&Self::Item) -> K1,
mut key2: impl FnMut(&Self::Item) -> K2,
) -> HashMap<K1, HashMap<K2, Vec<Self::Item>>>
where
K1: Eq + Hash,
K2: Eq + Hash,
{
let mut out: HashMap<K1, HashMap<K2, Vec<Self::Item>>> = HashMap::new();
for item in self {
out.entry(key1(&item))
.or_default()
.entry(key2(&item))
.or_default()
.push(item);
}
out
}
fn to_map_chain_reduce<K1, K2, A>(
self,
key1: impl FnMut(&Self::Item) -> K1,
key2: impl FnMut(&Self::Item) -> K2,
init: A,
mut reduce: impl FnMut(A, Self::Item) -> A,
) -> HashMap<K1, HashMap<K2, A>>
where
K1: Eq + Hash,
K2: Eq + Hash,
A: Clone,
{
self.to_map_chain(key1, key2)
.into_iter()
.map(|(k1, inner)| {
(
k1,
inner
.into_iter()
.map(|(k2, items)| {
let acc = items.into_iter().fold(init.clone(), &mut reduce);
(k2, acc)
})
.collect(),
)
})
.collect()
}
fn combine<J, K, KL, KR>(
self,
other: J,
key_left: KL,
key_right: KR,
) -> Combine<Self, J::IntoIter, K, KL, KR>
where
J: IntoIterator,
K: Eq + Hash + Clone,
KL: FnMut(&Self::Item) -> K,
KR: FnMut(&J::Item) -> K,
Self::Item: Clone,
J::Item: Clone,
{
Combine {
left: self,
key_left,
right: other.into_iter(),
key_right,
indexed: false,
idx: HashMap::new(),
pending: None,
}
}
fn combine_join<T, K, F>(self, key: F) -> Vec<Vec<T>>
where
Self::Item: IntoIterator<Item = T>,
K: Eq + Hash,
T: Clone,
F: FnMut(&T) -> K,
{
let mut key = key;
let mut acc: Vec<Vec<T>> = Vec::new();
let mut first = true;
for iterable in self {
let items: Vec<T> = iterable.into_iter().collect();
if first {
first = false;
acc = items.into_iter().map(|item| vec![item]).collect();
continue;
}
if acc.is_empty() {
continue;
}
let mut idx: HashMap<K, Vec<T>> = HashMap::new();
for item in items {
idx.entry(key(&item)).or_default().push(item);
}
let mut next_acc = Vec::new();
for row in acc {
if let Some(bucket) = idx.get(&key(&row[0])) {
for item in bucket {
let mut grown = row.clone();
grown.push(item.clone());
next_acc.push(grown);
}
}
}
acc = next_acc;
}
acc
}
fn distinct(self) -> Distinct<Self>
where
Self::Item: Eq + Hash + Clone,
{
Distinct {
iter: self,
seen: HashSet::new(),
}
}
fn distinct_by<K, F>(self, key: F) -> DistinctBy<Self, K, F>
where
K: Eq + Hash,
F: FnMut(&Self::Item) -> K,
{
DistinctBy {
iter: self,
key,
seen: HashSet::new(),
}
}
#[allow(clippy::wrong_self_convention)]
fn is_distinct(mut self) -> bool
where
Self::Item: Eq + Hash,
{
let mut seen = HashSet::new();
self.all(|item| seen.insert(item))
}
#[allow(clippy::wrong_self_convention)]
fn is_distinct_by<K>(mut self, mut key: impl FnMut(&Self::Item) -> K) -> bool
where
K: Eq + Hash,
{
let mut seen = HashSet::new();
self.all(|item| seen.insert(key(&item)))
}
fn when_empty<F>(self, fallback: F) -> WhenEmpty<Self, F>
where
F: IntoIterator<Item = Self::Item>,
{
WhenEmpty {
phase: WhenEmptyPhase::Source(self, false),
fallback: Some(fallback),
}
}
fn repeat(self, times: usize) -> Repeat<Self>
where
Self::Item: Clone,
{
Repeat {
source: self,
cache: Vec::new(),
times,
round: 0,
pos: 0,
}
}
fn sorted(self) -> Vec<Self::Item>
where
Self::Item: Ord,
{
let mut out: Vec<Self::Item> = self.collect();
out.sort();
out
}
fn sort_with<F>(self, mut compare: F) -> Vec<Self::Item>
where
F: FnMut(&Self::Item, &Self::Item) -> Ordering,
{
let mut out: Vec<Self::Item> = self.collect();
out.sort_by(&mut compare);
out
}
fn sort_by<K, F>(self, mut key: F) -> Vec<Self::Item>
where
K: Ord,
F: FnMut(&Self::Item) -> K,
{
let mut out: Vec<Self::Item> = self.collect();
out.sort_by_key(&mut key);
out
}
fn sort_by_desc<K, F>(self, mut key: F) -> Vec<Self::Item>
where
K: Ord,
F: FnMut(&Self::Item) -> K,
{
let mut out: Vec<Self::Item> = self.collect();
out.sort_by_key(|item| std::cmp::Reverse(key(item)));
out
}
fn avg(self) -> Option<f64>
where
Self::Item: Into<f64>,
{
let (mut sum, mut count) = (0f64, 0usize);
for item in self {
sum += item.into();
count += 1;
}
if count == 0 {
None
} else {
Some(sum / count as f64)
}
}
fn avg_by(self, mut value: impl FnMut(&Self::Item) -> f64) -> Option<f64> {
let (mut sum, mut count) = (0f64, 0usize);
for item in self {
sum += value(&item);
count += 1;
}
if count == 0 {
None
} else {
Some(sum / count as f64)
}
}
fn join(self, separator: &str) -> String
where
Self::Item: Display,
{
self.map(|item| item.to_string())
.collect::<Vec<String>>()
.join(separator)
}
fn join_by<S: Display>(
self,
mut value: impl FnMut(&Self::Item) -> S,
separator: &str,
) -> String {
self.map(|item| value(&item).to_string())
.collect::<Vec<String>>()
.join(separator)
}
fn has_exactly(self, n: usize) -> bool {
self.take(n.saturating_add(1)).count() == n
}
fn has_less_than(self, n: usize) -> bool {
self.take(n.saturating_add(1)).count() < n
}
fn has_less_or_exactly(self, n: usize) -> bool {
self.take(n.saturating_add(1)).count() <= n
}
fn has_more_than(self, n: usize) -> bool {
self.take(n.saturating_add(1)).count() > n
}
fn has_more_or_exactly(self, n: usize) -> bool {
self.take(n).count() >= n
}
fn reduce_and_map<A, R>(
self,
init: A,
mut fold: impl FnMut(A, Self::Item) -> A,
mut map: impl FnMut(A) -> R,
) -> R {
map(self.fold(init, &mut fold))
}
fn contains(mut self, item: &Self::Item) -> bool
where
Self::Item: PartialEq,
{
self.any(|x| &x == item)
}
}