rust_lodash/collection/iteration.rs
1/*!
2Iteration methods for Lodash-RS.
3
4This module provides iteration methods like `each`, `map`, `filter`, `reduce`, etc.
5These are the core methods for processing collections.
6*/
7
8use crate::collection::Collection;
9// Note: These imports are kept for future use in error handling and type constraints
10// use crate::utils::{LodashError, Result, Predicate, Mapper, Reducer};
11
12/// Iterate over elements of a collection, executing a function for each element.
13///
14/// # Examples
15///
16/// ```
17/// use rust_lodash::collection::iteration::each;
18///
19/// let mut sum = 0;
20/// each(&[1, 2, 3], |x| sum += x);
21/// assert_eq!(sum, 6);
22/// ```
23pub fn each<T, F>(collection: &[T], mut iteratee: F)
24where
25 F: FnMut(&T),
26{
27 for item in collection {
28 iteratee(item);
29 }
30}
31
32/// Alias for `each`.
33///
34/// # Examples
35///
36/// ```
37/// use rust_lodash::collection::iteration::for_each;
38///
39/// let mut sum = 0;
40/// for_each(&[1, 2, 3], |x| sum += x);
41/// assert_eq!(sum, 6);
42/// ```
43pub fn for_each<T, F>(collection: &[T], iteratee: F)
44where
45 F: FnMut(&T),
46{
47 each(collection, iteratee);
48}
49
50/// Create an array of values by running each element in collection through iteratee.
51///
52/// # Examples
53///
54/// ```
55/// use rust_lodash::collection::iteration::map;
56///
57/// let doubled = map(&[1, 2, 3], |x| x * 2);
58/// assert_eq!(doubled, vec![2, 4, 6]);
59///
60/// // Type conversion
61/// let strings = map(&[1, 2, 3], |x| x.to_string());
62/// assert_eq!(strings, vec!["1", "2", "3"]);
63/// ```
64pub fn map<T, U, F>(collection: &[T], iteratee: F) -> Vec<U>
65where
66 F: Fn(&T) -> U,
67{
68 collection.iter().map(iteratee).collect()
69}
70
71/// Iterate over elements of collection, returning an array of all elements
72/// the predicate returns truthy for.
73///
74/// # Examples
75///
76/// ```
77/// use rust_lodash::collection::iteration::filter;
78///
79/// let evens = filter(&[1, 2, 3, 4, 5], |x| x % 2 == 0);
80/// assert_eq!(evens, vec![2, 4]);
81/// ```
82pub fn filter<T, F>(collection: &[T], predicate: F) -> Vec<T>
83where
84 T: Clone,
85 F: Fn(&T) -> bool,
86{
87 collection.iter()
88 .filter(|item| predicate(item))
89 .cloned()
90 .collect()
91}
92
93/// Reduce collection to a value which is the accumulated result of running
94/// each element in collection through iteratee, where each successive
95/// invocation is supplied the return value of the previous.
96///
97/// # Examples
98///
99/// ```
100/// use rust_lodash::collection::iteration::reduce;
101///
102/// let sum = reduce(&[1, 2, 3, 4], |acc, x| acc + x, 0);
103/// assert_eq!(sum, 10);
104///
105/// // String concatenation
106/// let result = reduce(&["a", "b", "c"], |acc, x| format!("{}{}", acc, x), String::new());
107/// assert_eq!(result, "abc");
108/// ```
109pub fn reduce<T, U, F>(collection: &[T], iteratee: F, initial: U) -> U
110where
111 F: Fn(U, &T) -> U,
112{
113 collection.iter().fold(initial, iteratee)
114}
115
116/// This method is like `reduce` except that it iterates over elements of
117/// collection from right to left.
118///
119/// # Examples
120///
121/// ```
122/// use rust_lodash::collection::iteration::reduce_right;
123///
124/// let result = reduce_right(&["a", "b", "c"], |acc, x| format!("{}{}", acc, x), String::new());
125/// assert_eq!(result, "cba");
126/// ```
127pub fn reduce_right<T, U, F>(collection: &[T], iteratee: F, initial: U) -> U
128where
129 F: Fn(U, &T) -> U,
130{
131 collection.iter().rev().fold(initial, iteratee)
132}
133
134/// This method is like `each` except that it iterates over elements of
135/// collection from right to left.
136///
137/// # Examples
138///
139/// ```
140/// use rust_lodash::collection::iteration::for_each_right;
141///
142/// let mut result = Vec::new();
143/// for_each_right(&[1, 2, 3], |x| result.push(*x));
144/// assert_eq!(result, vec![3, 2, 1]);
145/// ```
146pub fn for_each_right<T, F>(collection: &[T], mut iteratee: F)
147where
148 F: FnMut(&T),
149{
150 for item in collection.iter().rev() {
151 iteratee(item);
152 }
153}
154
155/// Collection methods that work on the `Collection` type.
156impl<T> Collection<T> {
157 /// Iterate over elements of the collection, executing a function for each element.
158 ///
159 /// # Examples
160 ///
161 /// ```
162 /// use rust_lodash::collection::Collection;
163 ///
164 /// let collection = Collection::new(vec![1, 2, 3]);
165 /// let mut sum = 0;
166 /// collection.each(|x| sum += x);
167 /// assert_eq!(sum, 6);
168 /// ```
169 pub fn each<F>(&self, iteratee: F)
170 where
171 F: FnMut(&T),
172 {
173 each(&self.data, iteratee);
174 }
175
176 /// Create an array of values by running each element through iteratee.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// use rust_lodash::collection::Collection;
182 ///
183 /// let collection = Collection::new(vec![1, 2, 3]);
184 /// let doubled = collection.map(|x| x * 2);
185 /// assert_eq!(doubled, vec![2, 4, 6]);
186 /// ```
187 pub fn map<U, F>(&self, iteratee: F) -> Vec<U>
188 where
189 F: Fn(&T) -> U,
190 {
191 map(&self.data, iteratee)
192 }
193
194 /// Iterate over elements, returning an array of all elements
195 /// the predicate returns truthy for.
196 ///
197 /// # Examples
198 ///
199 /// ```
200 /// use rust_lodash::collection::Collection;
201 ///
202 /// let collection = Collection::new(vec![1, 2, 3, 4, 5]);
203 /// let evens = collection.filter(|x| x % 2 == 0);
204 /// assert_eq!(evens, vec![2, 4]);
205 /// ```
206 pub fn filter<F>(&self, predicate: F) -> Vec<T>
207 where
208 T: Clone,
209 F: Fn(&T) -> bool,
210 {
211 filter(&self.data, predicate)
212 }
213
214 /// Reduce the collection to a value which is the accumulated result
215 /// of running each element through iteratee.
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// use rust_lodash::collection::Collection;
221 ///
222 /// let collection = Collection::new(vec![1, 2, 3, 4]);
223 /// let sum = collection.reduce(|acc, x| acc + x, 0);
224 /// assert_eq!(sum, 10);
225 /// ```
226 pub fn reduce<U, F>(&self, iteratee: F, initial: U) -> U
227 where
228 F: Fn(U, &T) -> U,
229 {
230 reduce(&self.data, iteratee, initial)
231 }
232
233 /// This method is like `reduce` except that it iterates from right to left.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use rust_lodash::collection::Collection;
239 ///
240 /// let collection = Collection::new(vec!["a", "b", "c"]);
241 /// let result = collection.reduce_right(|acc, x| format!("{}{}", acc, x), String::new());
242 /// assert_eq!(result, "cba");
243 /// ```
244 pub fn reduce_right<U, F>(&self, iteratee: F, initial: U) -> U
245 where
246 F: Fn(U, &T) -> U,
247 {
248 reduce_right(&self.data, iteratee, initial)
249 }
250
251 /// This method is like `each` except that it iterates from right to left.
252 ///
253 /// # Examples
254 ///
255 /// ```
256 /// use rust_lodash::collection::Collection;
257 ///
258 /// let collection = Collection::new(vec![1, 2, 3]);
259 /// let mut result = Vec::new();
260 /// collection.for_each_right(|x| result.push(*x));
261 /// assert_eq!(result, vec![3, 2, 1]);
262 /// ```
263 pub fn for_each_right<F>(&self, iteratee: F)
264 where
265 F: FnMut(&T),
266 {
267 for_each_right(&self.data, iteratee);
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn test_each() {
277 let mut sum = 0;
278 each(&[1, 2, 3], |x| sum += x);
279 assert_eq!(sum, 6);
280 }
281
282 #[test]
283 fn test_for_each() {
284 let mut sum = 0;
285 for_each(&[1, 2, 3], |x| sum += x);
286 assert_eq!(sum, 6);
287 }
288
289 #[test]
290 fn test_map() {
291 let doubled = map(&[1, 2, 3], |x| x * 2);
292 assert_eq!(doubled, vec![2, 4, 6]);
293
294 let strings = map(&[1, 2, 3], std::string::ToString::to_string);
295 assert_eq!(strings, vec!["1", "2", "3"]);
296 }
297
298 #[test]
299 fn test_filter() {
300 let evens = filter(&[1, 2, 3, 4, 5], |x| x % 2 == 0);
301 assert_eq!(evens, vec![2, 4]);
302 }
303
304 #[test]
305 fn test_reduce() {
306 let sum = reduce(&[1, 2, 3, 4], |acc, x| acc + x, 0);
307 assert_eq!(sum, 10);
308
309 let result = reduce(&["a", "b", "c"], |acc, x| format!("{acc}{x}"), String::new());
310 assert_eq!(result, "abc");
311 }
312
313 #[test]
314 fn test_reduce_right() {
315 let result = reduce_right(&["a", "b", "c"], |acc, x| format!("{acc}{x}"), String::new());
316 assert_eq!(result, "cba");
317 }
318
319 #[test]
320 fn test_for_each_right() {
321 let mut result = Vec::new();
322 for_each_right(&[1, 2, 3], |x| result.push(*x));
323 assert_eq!(result, vec![3, 2, 1]);
324 }
325
326 #[test]
327 fn test_collection_each() {
328 let collection = Collection::new(vec![1, 2, 3]);
329 let mut sum = 0;
330 collection.each(|x| sum += x);
331 assert_eq!(sum, 6);
332 }
333
334 #[test]
335 fn test_collection_map() {
336 let collection = Collection::new(vec![1, 2, 3]);
337 let doubled = collection.map(|x| x * 2);
338 assert_eq!(doubled, vec![2, 4, 6]);
339 }
340
341 #[test]
342 fn test_collection_filter() {
343 let collection = Collection::new(vec![1, 2, 3, 4, 5]);
344 let evens = collection.filter(|x| x % 2 == 0);
345 assert_eq!(evens, vec![2, 4]);
346 }
347
348 #[test]
349 fn test_collection_reduce() {
350 let collection = Collection::new(vec![1, 2, 3, 4]);
351 let sum = collection.reduce(|acc, x| acc + x, 0);
352 assert_eq!(sum, 10);
353 }
354
355 #[test]
356 fn test_collection_reduce_right() {
357 let collection = Collection::new(vec!["a", "b", "c"]);
358 let result = collection.reduce_right(|acc, x| format!("{acc}{x}"), String::new());
359 assert_eq!(result, "cba");
360 }
361
362 #[test]
363 fn test_collection_for_each_right() {
364 let collection = Collection::new(vec![1, 2, 3]);
365 let mut result = Vec::new();
366 collection.for_each_right(|x| result.push(*x));
367 assert_eq!(result, vec![3, 2, 1]);
368 }
369
370 #[test]
371 fn test_empty_collection() {
372 let empty: Vec<i32> = vec![];
373 let result = map(&empty, |x| x * 2);
374 assert!(result.is_empty());
375
376 let sum = reduce(&empty, |acc, x| acc + x, 0);
377 assert_eq!(sum, 0);
378 }
379}