Skip to content

Commit e67fa45

Browse files
committed
Add fns IndexedRandom::choose_iter, choose_weighted_iter
1 parent 88b460e commit e67fa45

File tree

1 file changed

+53
-3
lines changed

1 file changed

+53
-3
lines changed

src/seq/slice.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,32 @@ pub trait IndexedRandom: Index<usize> {
6060
}
6161
}
6262

63+
/// Return an iterator which samples from `self` with replacement
64+
///
65+
/// Returns `None` if and only if `self.is_empty()`.
66+
///
67+
/// # Example
68+
///
69+
/// ```
70+
/// use rand::seq::IndexedRandom;
71+
///
72+
/// let choices = [1, 2, 4, 8, 16, 32];
73+
/// let mut rng = rand::rng();
74+
/// for choice in choices.choose_iter(&mut rng).unwrap().take(3) {
75+
/// println!("{:?}", choice);
76+
/// }
77+
/// ```
78+
fn choose_iter<R>(
79+
&self,
80+
rng: &mut R,
81+
) -> Option<impl Iterator<Item = &Self::Output>>
82+
where
83+
R: Rng + ?Sized,
84+
{
85+
let distr = crate::distr::Uniform::new(0, self.len()).ok()?;
86+
Some(rng.sample_iter(distr).map(|i| &self[i]))
87+
}
88+
6389
/// Uniformly sample `amount` distinct elements from self
6490
///
6591
/// Chooses `amount` elements from the slice at random, without repetition,
@@ -128,7 +154,7 @@ pub trait IndexedRandom: Index<usize> {
128154
/// Biased sampling for one element
129155
///
130156
/// Returns a reference to one element of the slice, sampled according
131-
/// to the provided weights. Returns `None` only if the slice is empty.
157+
/// to the provided weights. Returns `None` if and only if `self.is_empty()`.
132158
///
133159
/// The specified function `weight` maps each item `x` to a relative
134160
/// likelihood `weight(x)`. The probability of each item being selected is
@@ -166,9 +192,33 @@ pub trait IndexedRandom: Index<usize> {
166192
B: SampleBorrow<X>,
167193
X: SampleUniform + Weight + PartialOrd<X>,
168194
{
169-
use crate::distr::{weighted::WeightedIndex, Distribution};
195+
use crate::distr::weighted::WeightedIndex;
196+
let distr = WeightedIndex::new((0..self.len()).map(|idx| weight(&self[idx])))?;
197+
Ok(&self[rng.sample(distr)])
198+
}
199+
200+
/// Biased sampling with replacement
201+
///
202+
/// Returns an iterator which samples elements from `self` according to the
203+
/// given weights with replacement (i.e. elements may be repeated).
204+
/// Returns `None` if and only if `self.is_empty()`.
205+
///
206+
/// See also doc for [`Self::choose_weighted`].
207+
#[cfg(feature = "alloc")]
208+
fn choose_weighted_iter<R, F, B, X>(
209+
&self,
210+
rng: &mut R,
211+
weight: F,
212+
) -> Result<impl Iterator<Item = &Self::Output>, WeightError>
213+
where
214+
R: Rng + ?Sized,
215+
F: Fn(&Self::Output) -> B,
216+
B: SampleBorrow<X>,
217+
X: SampleUniform + Weight + PartialOrd<X>,
218+
{
219+
use crate::distr::weighted::WeightedIndex;
170220
let distr = WeightedIndex::new((0..self.len()).map(|idx| weight(&self[idx])))?;
171-
Ok(&self[distr.sample(rng)])
221+
Ok(rng.sample_iter(distr).map(|i| &self[i]))
172222
}
173223

174224
/// Biased sampling of `amount` distinct elements

0 commit comments

Comments
 (0)