use rand::{Rng, thread_rng};
pub fn reservoir_sample<T: Copy>(pool: &[T], reservoir_size: usize) -> Vec<T> {
assert!(pool.len() >= reservoir_size,
"Sample size is greater than total.");
let mut pool_mut = &pool[..];
let mut res = pool_mut[..reservoir_size].to_vec();
pool_mut = &pool_mut[reservoir_size..];
let mut ele_seen = reservoir_size;
let mut rng = thread_rng();
while pool_mut.len() > 0 {
ele_seen += 1;
let r = rng.gen_range(0, ele_seen);
let p_0 = pool_mut[0];
pool_mut = &pool_mut[1..];
if r < reservoir_size {
res[r] = p_0;
}
}
res
}
pub fn fisher_yates<T: Copy>(arr: &[T]) -> Vec<T> {
let n = arr.len();
let mut rng = thread_rng();
let mut shuffled_arr = Vec::with_capacity(n);
unsafe {
shuffled_arr.set_len(n);
}
for i in 0..n {
let j = rng.gen_range(0, i + 1);
if j != i {
let x = shuffled_arr[j];
shuffled_arr[i] = x;
}
shuffled_arr[j] = arr[i];
}
shuffled_arr
}
pub fn in_place_fisher_yates<T>(arr: &mut [T]) {
let n = arr.len();
let mut rng = thread_rng();
for i in 0..n {
let j = rng.gen_range(0, n - i);
arr.swap(i, i + j);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reservoir_sample() {
let a = vec![1, 2, 3, 4, 5, 6, 7];
let b = reservoir_sample(&a, 3);
assert_eq!(b.len(), 3);
}
#[test]
fn test_fisher_yates() {
let a = (0..10).collect::<Vec<_>>();
let b = fisher_yates(&a);
for val in a.iter() {
assert!(b.contains(val));
}
}
#[test]
fn test_in_place_fisher_yates() {
let mut a = (0..10).collect::<Vec<_>>();
in_place_fisher_yates(&mut a);
for val in 0..10 {
assert!(a.contains(&val));
}
}
}