1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/// Find all unique elements in a collection based on a key generated by the iteratee function.
/// Returns elements whose generated keys appear exactly once.
///
/// # Arguments
/// * `collection` - A slice of items.
/// * `iteratee` - A function that takes an item and returns a key used for uniqueness comparison.
///
/// # Returns
/// * `Vec<T>` - A vector containing only the elements whose generated keys appear exactly once.
///
/// # Examples
/// ```rust
/// use lowdash::find_uniques_by;
/// let numbers = vec![1, 2, 3, 4];
/// let result = find_uniques_by(&numbers, |x| x % 2); // Group by even/odd
/// assert_eq!(result, vec![]); // No unique remainders
/// ```
///
/// ```rust
/// use lowdash::find_uniques_by;
///
/// #[derive(Debug, Clone, PartialEq)]
/// struct Person {
/// name: String,
/// age: u32,
/// }
///
/// let people = vec![
/// Person { name: "Alice".to_string(), age: 25 },
/// Person { name: "Bob".to_string(), age: 30 },
/// Person { name: "Carol".to_string(), age: 25 },
/// ];
///
/// let result = find_uniques_by(&people, |p| p.age);
/// assert_eq!(result, vec![Person { name: "Bob".to_string(), age: 30 }]);
/// ```
pub fn find_uniques_by<T, U, F>(collection: &[T], iteratee: F) -> Vec<T>
where
T: Clone,
U: Eq + std::hash::Hash,
F: Fn(&T) -> U,
{
use std::collections::HashMap;
let mut key_counts = HashMap::new();
// Count occurrences of each key
for item in collection {
let key = iteratee(item);
*key_counts.entry(key).or_insert(0) += 1;
}
// Collect items whose keys appear exactly once
collection
.iter()
.filter(|item| key_counts.get(&iteratee(item)) == Some(&1))
.cloned()
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_uniques_by_remainder() {
let numbers = vec![1, 2, 3, 4];
let result = find_uniques_by(&numbers, |x| x % 2);
assert_eq!(result, vec![]); // No unique remainders
}
#[test]
fn test_find_uniques_by_length() {
let words = vec!["a", "ab", "abc", "ab", "abcd"];
let result = find_uniques_by(&words, |s| s.len());
assert_eq!(result, vec!["a", "abc", "abcd"]);
}
#[test]
fn test_find_uniques_by_empty() {
let collection: Vec<i32> = vec![];
let result = find_uniques_by(&collection, |x| x % 2);
assert_eq!(result, Vec::<i32>::new());
}
#[test]
fn test_find_uniques_by_with_struct() {
#[derive(Debug, Clone, PartialEq)]
struct Person {
name: String,
age: u32,
}
let people = vec![
Person {
name: "Alice".to_string(),
age: 25,
},
Person {
name: "Bob".to_string(),
age: 30,
},
Person {
name: "Carol".to_string(),
age: 25,
},
];
// Test uniqueness by age
let result = find_uniques_by(&people, |p| p.age);
assert_eq!(
result,
vec![Person {
name: "Bob".to_string(),
age: 30,
}]
);
// Test uniqueness by name first letter
let name_result = find_uniques_by(&people, |p| p.name.chars().next().unwrap());
assert_eq!(
name_result,
vec![
Person {
name: "Alice".to_string(),
age: 25,
},
Person {
name: "Bob".to_string(),
age: 30,
},
Person {
name: "Carol".to_string(),
age: 25,
}
]
);
}
#[test]
fn test_find_uniques_by_all_unique() {
let numbers = vec![1, 2, 3];
let result = find_uniques_by(&numbers, |x| x * 2);
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_find_uniques_by_all_same() {
let numbers = vec![1, 2, 3, 4];
let result = find_uniques_by(&numbers, |_| 1);
assert_eq!(result, Vec::<i32>::new());
}
}