|
|
|
@@ -0,0 +1,139 @@
|
|
|
|
|
use std::iter::Peekable;
|
|
|
|
|
|
|
|
|
|
use rand::{seq::SliceRandom, Rng};
|
|
|
|
|
|
|
|
|
|
/// Trait for creating random intersperse.
|
|
|
|
|
///
|
|
|
|
|
/// It's implemented for all iterables.
|
|
|
|
|
///
|
|
|
|
|
/// The usage is the following:
|
|
|
|
|
/// ```
|
|
|
|
|
/// let words = &[4, 5, 6];
|
|
|
|
|
/// let result = [1, 2, 3]
|
|
|
|
|
/// .into_iter()
|
|
|
|
|
/// .random_itersperse(words, &mut rand::thread_rng())
|
|
|
|
|
/// .collect::<Vec<_>>();
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// Now if you print the result, you'll see that
|
|
|
|
|
/// after every word from the source slice,
|
|
|
|
|
/// placed one word from the `words` slice.
|
|
|
|
|
/// Like this: `[1, 6, 2, 4, 3]`.
|
|
|
|
|
pub trait RandomIntersperse<'a, L, R>
|
|
|
|
|
where
|
|
|
|
|
L: IntoIterator,
|
|
|
|
|
R: Rng,
|
|
|
|
|
{
|
|
|
|
|
fn random_itersperse(
|
|
|
|
|
self,
|
|
|
|
|
choises: &'a [L::Item],
|
|
|
|
|
random: &'a mut R,
|
|
|
|
|
) -> RandomIntersperseStruct<'a, L, R>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Struct used to create `random_intresperse`.
|
|
|
|
|
/// It has a peekable iterator, a reference to a
|
|
|
|
|
/// random generator, a slice for items to choose from
|
|
|
|
|
/// and boolean to check current state.
|
|
|
|
|
///
|
|
|
|
|
/// The iterator is peekable, because we need to check
|
|
|
|
|
/// if next item exists, to avoid inserting
|
|
|
|
|
/// a generated value at the end of iterator.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct RandomIntersperseStruct<'a, L, R>
|
|
|
|
|
where
|
|
|
|
|
L: IntoIterator,
|
|
|
|
|
R: Rng,
|
|
|
|
|
{
|
|
|
|
|
iterator: Peekable<L::IntoIter>,
|
|
|
|
|
choices: &'a [L::Item],
|
|
|
|
|
random: &'a mut R,
|
|
|
|
|
use_iter: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Implement a `RandomIntersperse` trait for all
|
|
|
|
|
/// items that can be turned in iterators.
|
|
|
|
|
impl<'a, L, R> RandomIntersperse<'a, L, R> for L
|
|
|
|
|
where
|
|
|
|
|
L: IntoIterator,
|
|
|
|
|
R: Rng,
|
|
|
|
|
{
|
|
|
|
|
fn random_itersperse(
|
|
|
|
|
self,
|
|
|
|
|
choices: &'a [L::Item],
|
|
|
|
|
random: &'a mut R,
|
|
|
|
|
) -> RandomIntersperseStruct<'a, L, R> {
|
|
|
|
|
RandomIntersperseStruct {
|
|
|
|
|
random,
|
|
|
|
|
choices,
|
|
|
|
|
use_iter: true,
|
|
|
|
|
iterator: self.into_iter().peekable(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Implementation of an interator for a randomitersperse structure,
|
|
|
|
|
/// so it can be used in chain.
|
|
|
|
|
impl<'a, L, R> Iterator for RandomIntersperseStruct<'a, L, R>
|
|
|
|
|
where
|
|
|
|
|
L: IntoIterator,
|
|
|
|
|
R: Rng,
|
|
|
|
|
L::Item: Clone,
|
|
|
|
|
{
|
|
|
|
|
// The type of item is the same as for
|
|
|
|
|
// original iterator.
|
|
|
|
|
type Item = L::Item;
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
// Peek a value from the iterator to check if we have values.
|
|
|
|
|
self.iterator.peek()?;
|
|
|
|
|
|
|
|
|
|
let choise = self.choices.choose(self.random);
|
|
|
|
|
if choise.is_none() {
|
|
|
|
|
self.use_iter = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self.use_iter {
|
|
|
|
|
// We change use_iter, so a random
|
|
|
|
|
// value is chosen on the next step.
|
|
|
|
|
self.use_iter = false;
|
|
|
|
|
self.iterator.next()
|
|
|
|
|
} else {
|
|
|
|
|
self.use_iter = true;
|
|
|
|
|
self.choices.choose(self.random).cloned()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use crate::utils::inter_join::RandomIntersperse;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
pub fn success() {
|
|
|
|
|
let randoms = &[4, 5, 6];
|
|
|
|
|
let result = [1, 2, 3]
|
|
|
|
|
.into_iter()
|
|
|
|
|
.random_itersperse(randoms, &mut rand::thread_rng())
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
for value in [1, 2, 3] {
|
|
|
|
|
assert!(result.contains(&value));
|
|
|
|
|
}
|
|
|
|
|
assert_eq!(result.len(), 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
pub fn empty_array() {
|
|
|
|
|
let randoms = &[];
|
|
|
|
|
let result = [1, 2, 3]
|
|
|
|
|
.into_iter()
|
|
|
|
|
.random_itersperse(randoms, &mut rand::thread_rng())
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
for value in [1, 2, 3] {
|
|
|
|
|
assert!(result.contains(&value));
|
|
|
|
|
}
|
|
|
|
|
assert_eq!(result.len(), 3);
|
|
|
|
|
}
|
|
|
|
|
}
|