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}