mckernant1_tools/iter/
counting.rs

1use std::collections::HashMap;
2use std::hash::Hash;
3
4pub trait EachCount {
5    type Item;
6
7    /// gives a count of each unique item that exist
8    fn each_count(self) -> HashMap<Self::Item, u64>
9    where
10        Self::Item: Hash + Eq;
11
12    /// gives a count of each unique item decided by the selector
13    /// This is essentially map + each_count
14    fn each_count_by<K>(self, selector: fn(Self::Item) -> K) -> HashMap<K, u64>
15    where
16        K: Eq + Hash;
17}
18
19impl<I, T> EachCount for I
20where
21    I: IntoIterator<Item = T>,
22{
23    type Item = T;
24
25    fn each_count(self) -> HashMap<Self::Item, u64>
26    where
27        Self::Item: Hash + Eq,
28    {
29        let mut hm: HashMap<Self::Item, u64> = HashMap::new();
30
31        for item in self.into_iter() {
32            hm.entry(item).and_modify(|it| *it += 1).or_insert(1);
33        }
34        hm
35    }
36
37    fn each_count_by<K>(self, selector: fn(Self::Item) -> K) -> HashMap<K, u64>
38    where
39        K: Eq + Hash,
40    {
41        let mut hm: HashMap<K, u64> = HashMap::new();
42
43        for item in self.into_iter().map(|it| selector(it)) {
44            hm.entry(item).and_modify(|it| *it += 1).or_insert(1);
45        }
46        hm
47    }
48}
49
50#[cfg(test)]
51mod test {
52    use crate::iter::counting::EachCount;
53    use std::collections::HashMap;
54
55    #[derive(Clone, Hash, PartialEq, Eq, Debug)]
56    struct Test {
57        a: i64,
58        b: u64,
59    }
60
61    #[test]
62    fn test_each_count() {
63        let v = vec![1, 1, 1, 2, 3, 3, 3, 3];
64        let v = v.each_count();
65
66        assert_eq!(v, HashMap::from([(1, 3), (2, 1), (3, 4)]))
67    }
68
69    #[test]
70    fn test_each_count_by() {
71        let v = vec![
72            Test { a: 1, b: 1 },
73            Test { a: 1, b: 2 },
74            Test { a: 1, b: 2 },
75            Test { a: 2, b: 1 },
76            Test { a: 3, b: 1 },
77            Test { a: 3, b: 2 },
78            Test { a: 3, b: 2 },
79            Test { a: 3, b: 2 },
80        ];
81        let x = v.clone().each_count();
82        assert_eq!(
83            x,
84            HashMap::from([
85                (Test { a: 3, b: 2 }, 3),
86                (Test { a: 1, b: 2 }, 2),
87                (Test { a: 1, b: 1 }, 1),
88                (Test { a: 3, b: 1 }, 1),
89                (Test { a: 2, b: 1 }, 1)
90            ])
91        );
92        let v = v.each_count_by(|it| it.a);
93        assert_eq!(v, HashMap::from([(1, 3), (2, 1), (3, 4)]))
94    }
95}