循环 Rust 迭代器给定的次数
Cycle a Rust iterator a given number of times
如何在迭代器中循环有限次?
我希望这样的输出是 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3
然后停止:
vec![1, 2, 3].iter().cycle(4)
// ^ but .cycle() doesn't take an argument...
我不知道迭代器的长度。
标准库中没有这样的迭代器。
如果你知道迭代器的大小,你可以take
你的数字乘以迭代器的大小:
fn cycle_n_times<T: Clone>(slice: &[T], count: usize) -> impl Iterator<Item = &T> {
slice.iter().cycle().take(slice.len() * count)
}
或者您可以自己编写更通用的:
pub struct Ncycles<I> {
orig: I,
iter: I,
count: usize,
}
impl<I: Clone> Ncycles<I> {
fn new(iter: I, count: usize) -> Ncycles<I> {
Ncycles {
orig: iter.clone(),
iter,
count,
}
}
}
impl<I> Iterator for Ncycles<I>
where
I: Clone + Iterator,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
match self.iter.next() {
None if self.count == 0 => None,
None => {
self.iter = self.orig.clone();
self.count -= 1;
self.iter.next()
}
y => y,
}
}
}
#[test]
fn it_work() {
Ncycles::new(vec![1, 2, 3].iter(), 4).eq(&[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]);
}
一个简单的方法是重复迭代器本身,取前 4 个并展平:
fn main() {
let v = vec![1, 2, 3];
let res = std::iter::repeat(v.iter())
.take(4)
.flatten()
.collect::<Vec<_>>();
dbg!(res);
}
使用 this gist 中的代码比较 3 种不同方法的一些微基准测试结果:
- 在这个答案中重复-take-flatten
- 手卷环
- a
cycle_n
实现模仿 Iterator::cycle
.
荣誉 rustc
,cycle_n
在输入相当大时始终优于其他两个,而 repeat-take-flatten 对于小输入表现最佳。
可以利用 slice::repeat
,但我无法想象这是非常有效的:
let v = vec![1, 2, 3];
let it = v.iter();
println!("{:?}", it.map(|x| *x).collect::<Vec<i32>>().repeat(4).iter());
如何在迭代器中循环有限次?
我希望这样的输出是 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3
然后停止:
vec![1, 2, 3].iter().cycle(4)
// ^ but .cycle() doesn't take an argument...
我不知道迭代器的长度。
标准库中没有这样的迭代器。
如果你知道迭代器的大小,你可以take
你的数字乘以迭代器的大小:
fn cycle_n_times<T: Clone>(slice: &[T], count: usize) -> impl Iterator<Item = &T> {
slice.iter().cycle().take(slice.len() * count)
}
或者您可以自己编写更通用的:
pub struct Ncycles<I> {
orig: I,
iter: I,
count: usize,
}
impl<I: Clone> Ncycles<I> {
fn new(iter: I, count: usize) -> Ncycles<I> {
Ncycles {
orig: iter.clone(),
iter,
count,
}
}
}
impl<I> Iterator for Ncycles<I>
where
I: Clone + Iterator,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
match self.iter.next() {
None if self.count == 0 => None,
None => {
self.iter = self.orig.clone();
self.count -= 1;
self.iter.next()
}
y => y,
}
}
}
#[test]
fn it_work() {
Ncycles::new(vec![1, 2, 3].iter(), 4).eq(&[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]);
}
一个简单的方法是重复迭代器本身,取前 4 个并展平:
fn main() {
let v = vec![1, 2, 3];
let res = std::iter::repeat(v.iter())
.take(4)
.flatten()
.collect::<Vec<_>>();
dbg!(res);
}
使用 this gist 中的代码比较 3 种不同方法的一些微基准测试结果:
- 在这个答案中重复-take-flatten
- 手卷环
- a
cycle_n
实现模仿Iterator::cycle
.
荣誉 rustc
,cycle_n
在输入相当大时始终优于其他两个,而 repeat-take-flatten 对于小输入表现最佳。
可以利用 slice::repeat
,但我无法想象这是非常有效的:
let v = vec![1, 2, 3];
let it = v.iter();
println!("{:?}", it.map(|x| *x).collect::<Vec<i32>>().repeat(4).iter());