我想要类似这样的伪代码:
a = [1, 2, 3, 4];
b = [3, 4, 5, 6];
iter = a.iter_mut().zip(b.iter_mut());
shuffle(iter);
// example shuffle:
// a = [2, 4, 3, 1];
// b = [4, 6, 5, 3];
更具体地说,是否有一些功能类似于:
fn shuffle<T>(iterator: IterMut<T>) { /* ... */ }
我的具体情况是尝试按行和向量Array2
改写(array2:Lndarray:Array2<f32>, vec:Vec<usize>)
。
特别是array2.iter_axis(Axis(1)).zip(vec.iter())
。
答案 0 :(得分:0)
无法就地改组通用迭代器。
但是,对切片执行改组很容易:
use rand::Rng;
pub fn shufflex<T: Copy>(slice: &mut [T]) {
let mut rng = rand::thread_rng();
let len = slice.len();
for i in 0..len {
let next = rng.gen_range(i, len);
let tmp = slice[i];
slice[i] = slice[next];
slice[next] = tmp;
}
}
但是也可以编写更通用的shuffle
函数,该函数可用于多种类型:
use std::ops::{Index, IndexMut};
use rand::Rng;
pub fn shuffle<T>(indexable: &mut T)
where
T: IndexMut<usize> + Len + ?Sized,
T::Output: Copy,
{
let mut rng = rand::thread_rng();
let len = indexable.len();
for i in 0..len {
let next = rng.gen_range(i, len);
let tmp = indexable[i];
indexable[i] = indexable[next];
indexable[next] = tmp;
}
}
我写了一个完整的示例,该示例还允许对playground中的多个切片进行改组。
编辑:我想我误会了你想做什么。要以相同方式随机播放多个切片,我将执行this:
use rand::Rng;
pub fn shuffle<T: Copy>(slices: &mut [&mut [T]]) {
if slices.len() > 0 {
let mut rng = rand::thread_rng();
let len = slices[0].len();
assert!(slices.iter().all(|s| s.len() == len));
for i in 0..len {
let next = rng.gen_range(i, len);
for slice in slices.iter_mut() {
let tmp: T = slice[i];
slice[i] = slice[next];
slice[next] = tmp;
}
}
}
}
答案 1 :(得分:0)
要以相同顺序随机播放,您可以首先记住该顺序,然后在每次随机播放中都重复使用它。从rand crate的Fisher-Yates洗牌开始:
fn shuffle<R>(&mut self, rng: &mut R)
where R: Rng + ?Sized {
for i in (1..self.len()).rev() {
self.swap(i, gen_index(rng, i + 1));
}
}
事实证明,我们需要为1和切片长度之间的每个i + 1
存储0和i
之间的随机数,其顺序相反:
// create a vector of indices for shuffling slices of given length
let indices: Vec<usize> = {
let mut rng = rand::thread_rng();
(1..slice_len).rev()
.map(|i| rng.gen_range(0, i + 1))
.collect()
};
然后,我们可以实现shuffle的变体,其中我们从上面的随机索引列表中提取它们,而不是生成新的随机数:
// shuffle SLICE taking indices from the provided vector
for (i, &rnd_ind) in (1..slice.len()).rev().zip(&indices) {
slice.swap(i, rnd_ind);
}
将两者放在一起,您可以使用类似(playground)的方法以相同顺序随机播放多个切片:
pub fn shuffle<T>(slices: &mut [&mut [T]]) {
if slices.len() == 0 {
return;
}
let indices: Vec<usize> = {
let mut rng = rand::thread_rng();
(1..slices[0].len())
.rev()
.map(|i| rng.gen_range(0, i + 1))
.collect()
};
for slice in slices {
assert_eq!(slice.len(), indices.len() + 1);
for (i, &rnd_ind) in (1..slice.len()).rev().zip(&indices) {
slice.swap(i, rnd_ind);
}
}
}