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}