rust_lodash/collection/
operation.rs

1/*!
2Collection operation methods for Lodash-RS.
3
4This module provides collection operation methods like `shuffle`, `sample`, `size`, etc.
5These methods are used to manipulate and analyze collections.
6*/
7
8use crate::collection::Collection;
9// Note: These imports are kept for future use in error handling
10// use crate::utils::{LodashError, Result};
11use rand::seq::SliceRandom;
12use rand::thread_rng;
13
14/// Get the size of collection.
15/// 
16/// # Examples
17/// 
18/// ```
19/// use rust_lodash::collection::operation::size;
20/// 
21/// let numbers = vec![1, 2, 3, 4, 5];
22/// assert_eq!(size(&numbers), 5);
23/// 
24/// let empty: Vec<i32> = vec![];
25/// assert_eq!(size(&empty), 0);
26/// ```
27pub fn size<T>(collection: &[T]) -> usize {
28    collection.len()
29}
30
31/// Creates an array of shuffled values.
32/// 
33/// # Examples
34/// 
35/// ```
36/// use rust_lodash::collection::operation::shuffle;
37/// 
38/// let numbers = vec![1, 2, 3, 4, 5];
39/// let shuffled = shuffle(&numbers);
40/// assert_eq!(shuffled.len(), 5);
41/// // Note: The order will be different, but all elements will be present
42/// ```
43pub fn shuffle<T>(collection: &[T]) -> Vec<T>
44where
45    T: Clone,
46{
47    let mut shuffled = collection.to_vec();
48    shuffled.shuffle(&mut thread_rng());
49    shuffled
50}
51
52/// Gets a random element from collection.
53/// 
54/// # Examples
55/// 
56/// ```
57/// use rust_lodash::collection::operation::sample;
58/// 
59/// let numbers = vec![1, 2, 3, 4, 5];
60/// let random = sample(&numbers);
61/// assert!(numbers.contains(random.unwrap()));
62/// ```
63pub fn sample<T>(collection: &[T]) -> Option<&T> {
64    if collection.is_empty() {
65        return None;
66    }
67    collection.choose(&mut thread_rng())
68}
69
70/// Gets n random elements at unique keys from collection up to the size of collection.
71/// 
72/// # Examples
73/// 
74/// ```
75/// use rust_lodash::collection::operation::sample_size;
76/// 
77/// let numbers = vec![1, 2, 3, 4, 5];
78/// let samples = sample_size(&numbers, 3);
79/// assert_eq!(samples.len(), 3);
80/// // All samples will be unique elements from the original collection
81/// ```
82pub fn sample_size<T>(collection: &[T], n: usize) -> Vec<T>
83where
84    T: Clone,
85{
86    if collection.is_empty() || n == 0 {
87        return Vec::new();
88    }
89    
90    let mut rng = thread_rng();
91    let mut samples = collection.to_vec();
92    samples.shuffle(&mut rng);
93    samples.truncate(n);
94    samples
95}
96
97/// Collection methods that work on the `Collection` type.
98impl<T> Collection<T> {
99    /// Get the size of the collection.
100    /// 
101    /// # Examples
102    /// 
103    /// ```
104    /// use rust_lodash::collection::Collection;
105    /// 
106    /// let collection = Collection::new(vec![1, 2, 3, 4, 5]);
107    /// assert_eq!(collection.size(), 5);
108    /// ```
109    #[must_use]
110    pub fn size(&self) -> usize {
111        size(&self.data)
112    }
113
114    /// Creates an array of shuffled values.
115    /// 
116    /// # Examples
117    /// 
118    /// ```
119    /// use rust_lodash::collection::Collection;
120    /// 
121    /// let collection = Collection::new(vec![1, 2, 3, 4, 5]);
122    /// let shuffled = collection.shuffle();
123    /// assert_eq!(shuffled.len(), 5);
124    /// ```
125    #[must_use]
126    pub fn shuffle(&self) -> Vec<T>
127    where
128        T: Clone,
129    {
130        shuffle(&self.data)
131    }
132
133    /// Gets a random element from the collection.
134    /// 
135    /// # Examples
136    /// 
137    /// ```
138    /// use rust_lodash::collection::Collection;
139    /// 
140    /// let collection = Collection::new(vec![1, 2, 3, 4, 5]);
141    /// let random = collection.sample();
142    /// assert!(collection.data().contains(random.unwrap()));
143    /// ```
144    #[must_use]
145    pub fn sample(&self) -> Option<&T> {
146        sample(&self.data)
147    }
148
149    /// Gets n random elements at unique keys from the collection.
150    /// 
151    /// # Examples
152    /// 
153    /// ```
154    /// use rust_lodash::collection::Collection;
155    /// 
156    /// let collection = Collection::new(vec![1, 2, 3, 4, 5]);
157    /// let samples = collection.sample_size(3);
158    /// assert_eq!(samples.len(), 3);
159    /// ```
160    #[must_use]
161    pub fn sample_size(&self, n: usize) -> Vec<T>
162    where
163        T: Clone,
164    {
165        sample_size(&self.data, n)
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn test_size() {
175        let numbers = vec![1, 2, 3, 4, 5];
176        assert_eq!(size(&numbers), 5);
177
178        let empty: Vec<i32> = vec![];
179        assert_eq!(size(&empty), 0);
180    }
181
182    #[test]
183    fn test_shuffle() {
184        let numbers = vec![1, 2, 3, 4, 5];
185        let shuffled = shuffle(&numbers);
186        assert_eq!(shuffled.len(), 5);
187        
188        // Check that all elements are present (order may be different)
189        for num in &numbers {
190            assert!(shuffled.contains(num));
191        }
192    }
193
194    #[test]
195    fn test_sample() {
196        let numbers = vec![1, 2, 3, 4, 5];
197        let random = sample(&numbers);
198        assert!(random.is_some());
199        assert!(numbers.contains(random.unwrap()));
200
201        let empty: Vec<i32> = vec![];
202        assert_eq!(sample(&empty), None);
203    }
204
205    #[test]
206    fn test_sample_size() {
207        let numbers = vec![1, 2, 3, 4, 5];
208        let samples = sample_size(&numbers, 3);
209        assert_eq!(samples.len(), 3);
210        
211        // Check that all samples are from the original collection
212        for sample in &samples {
213            assert!(numbers.contains(sample));
214        }
215
216        // Test with n larger than collection size
217        let samples_large = sample_size(&numbers, 10);
218        assert_eq!(samples_large.len(), 5);
219
220        // Test with n = 0
221        let samples_zero = sample_size(&numbers, 0);
222        assert!(samples_zero.is_empty());
223
224        // Test with empty collection
225        let empty: Vec<i32> = vec![];
226        let samples_empty = sample_size(&empty, 3);
227        assert!(samples_empty.is_empty());
228    }
229
230    #[test]
231    fn test_collection_size() {
232        let collection = Collection::new(vec![1, 2, 3, 4, 5]);
233        assert_eq!(collection.size(), 5);
234    }
235
236    #[test]
237    fn test_collection_shuffle() {
238        let collection = Collection::new(vec![1, 2, 3, 4, 5]);
239        let shuffled = collection.shuffle();
240        assert_eq!(shuffled.len(), 5);
241        
242        // Check that all elements are present
243        for num in collection.data() {
244            assert!(shuffled.contains(num));
245        }
246    }
247
248    #[test]
249    fn test_collection_sample() {
250        let collection = Collection::new(vec![1, 2, 3, 4, 5]);
251        let random = collection.sample();
252        assert!(random.is_some());
253        assert!(collection.data().contains(random.unwrap()));
254
255        let empty: Collection<i32> = Collection::empty();
256        assert_eq!(empty.sample(), None);
257    }
258
259    #[test]
260    fn test_collection_sample_size() {
261        let collection = Collection::new(vec![1, 2, 3, 4, 5]);
262        let samples = collection.sample_size(3);
263        assert_eq!(samples.len(), 3);
264        
265        // Check that all samples are from the original collection
266        for sample in &samples {
267            assert!(collection.data().contains(sample));
268        }
269    }
270
271    #[test]
272    fn test_empty_collection_operations() {
273        let empty: Vec<i32> = vec![];
274        assert_eq!(size(&empty), 0);
275        assert!(shuffle(&empty).is_empty());
276        assert_eq!(sample(&empty), None);
277        assert!(sample_size(&empty, 3).is_empty());
278    }
279}