Skip to main content

ferroui_dynamic_data/kernel/
enumerable_ex.rs

1//! `EnumerableEx` of the kernel (`Kernel/EnumerableEx.cs`): helpers of sequences.
2//!
3//! `AsArray` and `AsList` are `Vec` and `collect` in Rust; the internal `EmptyIfNull`,
4//! `EnumerateOne`, `ForEach` and `ToHashSet` are `unwrap_or_default`, `std::iter::once`,
5//! `for_each` and `collect::<HashSet<_>>`.
6
7use super::ItemWithIndex;
8use std::collections::HashMap;
9use std::hash::Hash;
10
11/// The items whose value by `value_selector` is that of another item, group by group in the order
12/// of the first item of each group (`Duplicates`).
13pub fn duplicates<T, V: Eq + Hash>(source: impl IntoIterator<Item = T>, value_selector: impl Fn(&T) -> V) -> Vec<T> {
14    let mut groups: Vec<Vec<T>> = Vec::new();
15    let mut group_of_value: HashMap<V, usize> = HashMap::new();
16    for item in source {
17        let value = value_selector(&item);
18        match group_of_value.get(&value) {
19            Some(&group) => groups[group].push(item),
20            None => {
21                group_of_value.insert(value, groups.len());
22                groups.push(vec![item]);
23            }
24        }
25    }
26    groups.into_iter().filter(|group| group.len() > 1).flatten().collect()
27}
28
29/// The items of `items_to_find` that are in `source`, with their indexes there, in the order of
30/// `items_to_find` (`IndexOfMany(IEnumerable<T>, IEnumerable<T>)`).
31pub fn index_of_many<T: PartialEq + Clone>(source: &[T], items_to_find: &[T]) -> Vec<ItemWithIndex<T>> {
32    index_of_many_with(source, items_to_find, |item, index| ItemWithIndex::new(item.clone(), index))
33}
34
35/// [`index_of_many`] with the result that `result_selector` makes of each item and its index
36/// (`IndexOfMany(.., Func<TObject, int, TResult>)`).
37pub fn index_of_many_with<T: PartialEq, R>(source: &[T], items_to_find: &[T], result_selector: impl Fn(&T, usize) -> R) -> Vec<R> {
38    let mut result = Vec::new();
39    for item in items_to_find {
40        for (index, element) in source.iter().enumerate() {
41            if element == item {
42                result.push(result_selector(element, index));
43            }
44        }
45    }
46    result
47}
48
49/// The items with their indexes (`WithIndex`).
50pub fn with_index<T>(source: impl IntoIterator<Item = T>) -> Vec<ItemWithIndex<T>> {
51    source.into_iter().enumerate().map(|(index, item)| ItemWithIndex::new(item, index)).collect()
52}