cs_utils/test/
pick_random.rs

1use std::collections::HashSet;
2use rand::distributions::uniform::SampleRange;
3
4use crate::random_number;
5
6/// Picks random N items from a vector or slice of items.
7/// 
8/// ### Panics
9/// 
10/// * if items_count is larger than total number of items
11///   in a collection
12/// 
13/// ### Examples
14/// 
15/// ```
16/// #[cfg(any(features = "test", test))]
17/// {
18///     use cs_utils::test::pick_random;
19/// 
20///     let test_vector = vec![1, 2, 3, 4, 5, 6];
21///     let random_items = pick_random(&test_vector, 3);
22///     
23///     assert_eq!(
24///         random_items.len(),
25///         3,
26///         "Must have 3 items.",
27///     );
28/// 
29///     for item in random_items {
30///         assert!(
31///             test_vector.contains(item),
32///         );
33///     }
34/// }
35/// ```
36pub fn pick_random<'a, T>(
37    collection: &'a [T],
38    items_count: usize,
39) -> Vec<&'a T> {
40    let iter = collection.iter();
41    let (_, len) = iter.size_hint();
42    let len = len.expect("Gennot get iterator length.");
43
44    assert!(
45        items_count <= len,
46        "Count must be smaller or equal to item length.",
47    );
48
49    let mut set = HashSet::new();
50    while set.len() < items_count {
51        set.insert(
52            random_number(0..len)
53        );
54    };
55
56    let result = iter
57        .enumerate()
58        .filter_map(|(index, item)| {
59            if set.contains(&index) {
60                return Some(item);
61            }
62
63            return None;
64        }).collect();
65
66    return result;
67}
68
69/// Picks random items from a vector or slice of items.
70/// 
71/// ### Panics
72/// 
73/// * if items_count is larger than total number of items
74///   in a collection
75/// 
76/// ### Examples
77/// 
78/// ```
79/// #[cfg(any(features = "test", test))]
80/// {
81///     use cs_utils::test::pick_random_rg;
82/// 
83///     let test_vector = vec![1, 2, 3, 4, 5, 6];
84///     let random_items = pick_random_rg(&test_vector, 2..=3);
85///     
86///     assert!(
87///         random_items.len() >= 2,
88///         "Must have at least 2 items.",
89///     );
90/// 
91///     assert!(
92///         random_items.len() <= 3,
93///         "Must have at most 3 items.",
94///     );
95/// 
96///     for item in random_items {
97///         assert!(
98///             test_vector.contains(item),
99///         );
100///     }
101/// }
102/// ```
103pub fn pick_random_rg<'a, T, R: SampleRange<usize>>(
104    collection: &'a [T],
105    range: R,
106) -> Vec<&'a T> {
107    let items_count = random_number(range);
108
109    return pick_random(collection, items_count);
110
111}
112
113#[cfg(test)]
114mod tests {
115    use crate::traits::Random;
116    use crate::random_number;
117
118    impl Random for u8 {
119        fn random() -> Self {
120            return random_number(0..=u8::MAX);
121        }
122    }
123
124    mod pick_random {
125        use random_vec::random_vec_rg;
126        use crate::{random_number, test::{random_vec, pick_random}};
127
128        #[test]
129        fn picks_random_items_from_vector() {
130            let test_vector: Vec<u8> = random_vec_rg(100..=200);
131            let original_test_vector_length = test_vector.len();
132
133            let items_count = random_number(30..=50);
134            let random_items = pick_random(&test_vector, items_count);
135
136            assert_eq!(
137                random_items.len(),
138                items_count,
139                "Must return vector with {} references.", items_count,
140            );
141
142            assert_eq!(
143                test_vector.len(),
144                original_test_vector_length,
145                "Test vector must not change.",
146            );
147
148            for item in random_items {
149                assert!(
150                    test_vector.contains(item),
151                    "Test vector must contain random item.",
152                );
153            }
154        }
155
156        #[test]
157        fn picks_random_items_from_slice() {
158            let test_vector: Vec<u8> = random_vec_rg(100..=200);
159            let original_test_vector_length = test_vector.len();
160
161            let items_count = random_number(3..=5);
162            let random_items = pick_random(&test_vector[..], items_count);
163
164            assert_eq!(
165                random_items.len(),
166                items_count,
167                "Must return vector with {} references.", items_count,
168            );
169
170            assert_eq!(
171                test_vector.len(),
172                original_test_vector_length,
173                "Test vector must not change.",
174            );
175
176            for item in random_items {
177                assert!(
178                    test_vector.contains(item),
179                    "Test vector must contain random item.",
180                );
181            }
182        }
183    }
184
185    mod pick_random_rg {
186        use random_vec::random_vec_rg;
187        use crate::{test::{random_vec, pick_random_rg}};
188
189        #[test]
190        fn picks_random_items_from_vector() {
191            let test_vector: Vec<u8> = random_vec_rg(100..=200);
192            let original_test_vector_length = test_vector.len();
193
194            let random_items = pick_random_rg(&test_vector, 30..=50);
195
196            assert!(
197                random_items.len() >= 30,
198                "Must return vector with at least 30 references.",
199            );
200
201            assert!(
202                random_items.len() <= 50,
203                "Must return vector with at most 50 references.",
204            );
205
206            assert_eq!(
207                test_vector.len(),
208                original_test_vector_length,
209                "Test vector must not change.",
210            );
211
212            for item in random_items {
213                assert!(
214                    test_vector.contains(item),
215                    "Test vector must contain random item.",
216                );
217            }
218        }
219
220        #[test]
221        fn picks_random_items_from_slice() {
222            let test_vector: Vec<u8> = random_vec_rg(100..=200);
223            let original_test_vector_length = test_vector.len();
224
225            let random_items = pick_random_rg(&test_vector[..], 30..=50);
226
227            assert!(
228                random_items.len() >= 30,
229                "Must return vector with at least 30 references.",
230            );
231
232            assert!(
233                random_items.len() <= 50,
234                "Must return vector with at most 50 references.",
235            );
236
237            assert_eq!(
238                test_vector.len(),
239                original_test_vector_length,
240                "Test vector must not change.",
241            );
242
243            for item in random_items {
244                assert!(
245                    test_vector.contains(item),
246                    "Test vector must contain random item.",
247                );
248            }
249        }
250    }
251}