count_invert/
lib.rs

1use itertools::Itertools;
2use std::collections::HashMap;
3use std::hash::Hash;
4
5/// Converts a vector into a HashMap where the keys are the elements of the vector
6/// and the values are the counts of each element.
7#[inline]
8pub fn into_counts<T>(source: Vec<T>) -> HashMap<T, usize>
9where
10    T: Eq + Hash,
11{
12    source.into_iter().counts()
13}
14
15/// Inverts a HashMap such that the keys become the values and the values become the keys.
16/// The resulting HashMap maps the original values to a vector of keys that had that value.
17#[inline]
18pub fn invert_map<T>(source: HashMap<T, usize>) -> HashMap<usize, Vec<T>>
19where
20    T: Eq + Hash + Clone,
21{
22    let mut m: HashMap<usize, Vec<T>> = HashMap::new();
23    for (key, value) in source {
24        m.entry(value).or_default().push(key);
25    }
26    m
27}
28
29/// Converts a vector into a HashMap where the keys are the counts of elements
30/// and the values are vectors of elements that have that count.
31#[inline]
32pub fn into_count_map<T>(source: Vec<T>) -> HashMap<usize, Vec<T>>
33where
34    T: Eq + Hash + Clone,
35{
36    let counts = into_counts(source);
37    invert_map(counts)
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use std::collections::HashSet;
44
45    #[test]
46    fn test_into_counts_empty() {
47        let vec: Vec<i32> = Vec::new();
48        let expected: HashMap<i32, usize> = HashMap::new();
49        assert_eq!(into_counts(vec), expected);
50    }
51
52    #[test]
53    fn test_into_counts_single_element() {
54        let vec = vec![1];
55        let mut expected = HashMap::new();
56        expected.insert(1, 1);
57        assert_eq!(into_counts(vec), expected);
58    }
59
60    #[test]
61    fn test_into_counts_multiple_identical_elements() {
62        let vec = vec![1, 1, 1, 1];
63        let mut expected = HashMap::new();
64        expected.insert(1, 4);
65        assert_eq!(into_counts(vec), expected);
66    }
67
68    #[test]
69    fn test_into_counts_mixed_elements() {
70        let vec = vec![1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
71        let mut expected = HashMap::new();
72        expected.insert(1, 1);
73        expected.insert(2, 2);
74        expected.insert(3, 3);
75        expected.insert(4, 4);
76        assert_eq!(into_counts(vec), expected);
77    }
78
79    #[test]
80    fn test_into_counts_non_integer_elements() {
81        let vec = vec!["a", "b", "b", "c", "c", "c"];
82        let mut expected = HashMap::new();
83        expected.insert("a", 1);
84        expected.insert("b", 2);
85        expected.insert("c", 3);
86        assert_eq!(into_counts(vec), expected);
87    }
88
89    #[derive(Hash, Eq, PartialEq, Clone, Debug)]
90    struct TestStruct {
91        value: i32,
92    }
93
94    #[test]
95    fn test_into_counts_custom_struct() {
96        let vec = vec![
97            TestStruct { value: 1 },
98            TestStruct { value: 2 },
99            TestStruct { value: 2 },
100        ];
101        let mut expected = HashMap::new();
102        expected.insert(TestStruct { value: 1 }, 1);
103        expected.insert(TestStruct { value: 2 }, 2);
104        assert_eq!(into_counts(vec), expected);
105    }
106
107    #[test]
108    fn test_invert_map_single_value() {
109        let mut map = HashMap::new();
110        map.insert(1, 1);
111        let mut expected = HashMap::new();
112        expected.insert(1, vec![1]);
113        assert_eq!(invert_map(map), expected);
114    }
115
116    #[test]
117    fn test_invert_map_multiple_values() {
118        let mut map = HashMap::new();
119        map.insert(1, 2);
120        map.insert(2, 2);
121        map.insert(3, 3);
122        let mut expected = HashMap::new();
123        expected.insert(2, vec![1, 2]);
124        expected.insert(3, vec![3]);
125
126        // Convert vectors to sets for comparison
127        let result = invert_map(map)
128            .into_iter()
129            .map(|(k, v)| (k, v.into_iter().collect::<HashSet<_>>()))
130            .collect::<HashMap<_, _>>();
131
132        let expected = expected
133            .into_iter()
134            .map(|(k, v)| (k, v.into_iter().collect::<HashSet<_>>()))
135            .collect::<HashMap<_, _>>();
136
137        assert_eq!(result, expected);
138    }
139
140    #[test]
141    fn test_invert_map_empty() {
142        let map: HashMap<i32, usize> = HashMap::new();
143        let expected: HashMap<usize, Vec<i32>> = HashMap::new();
144        assert_eq!(invert_map(map), expected);
145    }
146
147    #[test]
148    fn test_into_count_map_empty() {
149        let vec: Vec<i32> = Vec::new();
150        let expected: HashMap<usize, Vec<i32>> = HashMap::new();
151        assert_eq!(into_count_map(vec), expected);
152    }
153
154    #[test]
155    fn test_into_count_map_single_element() {
156        let vec = vec![1];
157        let mut expected = HashMap::new();
158        expected.insert(1, vec![1]);
159        assert_eq!(into_count_map(vec), expected);
160    }
161
162    #[test]
163    fn test_into_count_map_mixed_elements() {
164        let vec = vec![1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
165        let mut expected = HashMap::new();
166        expected.insert(1, vec![1]);
167        expected.insert(2, vec![2]);
168        expected.insert(3, vec![3]);
169        expected.insert(4, vec![4]);
170        // Use HashSet to compare vectors irrespective of their order
171        for (key, value) in into_count_map(vec) {
172            let expected_set: HashSet<_> = expected.remove(&key).unwrap().into_iter().collect();
173            let result_set: HashSet<_> = value.into_iter().collect();
174            assert_eq!(expected_set, result_set);
175        }
176    }
177
178    #[test]
179    fn test_large_input() {
180        let vec: Vec<i32> = (0..1000).collect();
181        let counts = into_counts(vec.clone());
182        for i in 0..1000 {
183            assert_eq!(counts.get(&i), Some(&1));
184        }
185        let inverted = invert_map(counts);
186        for i in 0..1000 {
187            assert_eq!(inverted.get(&1).unwrap().contains(&i), true);
188        }
189        let count_map = into_count_map(vec);
190        for i in 0..1000 {
191            assert_eq!(count_map.get(&1).unwrap().contains(&i), true);
192        }
193    }
194}
195