一次迭代多个变量可能很有用,重叠(slice::windows
),或不是(slice::chunks
)。是否有等价于slice :: chunks/windows迭代器来循环对,三元组等?
这只适用于切片;有没有可能为迭代器做到这一点,为了方便使用元组?
像下面这样可以写成:
for (prev, next) in some_iter.windows(2) {
...
}
如果没有,可以把它作为对现有迭代器特性来实现?
一次迭代多个变量可能很有用,重叠(slice::windows
),或不是(slice::chunks
)。是否有等价于slice :: chunks/windows迭代器来循环对,三元组等?
这只适用于切片;有没有可能为迭代器做到这一点,为了方便使用元组?
像下面这样可以写成:
for (prev, next) in some_iter.windows(2) {
...
}
如果没有,可以把它作为对现有迭代器特性来实现?
TL; DR:有chunks
和windows
上的任意迭代器/收集最好的办法是先collect
它变成一个Vec
和迭代该。
请求的确切语法在Rust中是不可能的。
的问题是,在防锈,一个函数的签名取决于类型,不值,虽然依赖打字存在,也有实现它的(很难)几种语言。
这就是为什么chunks
和windows
顺便返回一个子片; &[T]
中的元素数量不是该类型的一部分,因此可以在运行时决定。
让我们假装你问:for slice in some_iter.windows(2)
而不是。
这个切片的存储位置在哪里?
它不能住:
LinkedList
没有一个连续的存储,因为Iterator::Item
定义的迭代器因此,不幸的是,切片只能在后备存储是切片时使用。
如果动态分配被接受,则有可能使用Vec<Iterator::Item>
作为分块的迭代器的Item
。
struct Chunks<I: Iterator> {
elements: Vec<<I as Iterator>::Item>,
underlying: I,
}
impl<I: Iterator> Chunks<I> {
fn new(iterator: I, size: usize) -> Chunks<I> {
assert!(size > 0);
let mut result = Chunks {
underlying: iterator, elements: Vec::with_capacity(size)
};
result.refill(size);
result
}
fn refill(&mut self, size: usize) {
assert!(self.elements.is_empty());
for _ in 0..size {
match self.underlying.next() {
Some(item) => self.elements.push(item),
None => break,
}
}
}
}
impl<I: Iterator> Iterator for Chunks<I> {
type Item = Vec<<I as Iterator>::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.elements.is_empty() {
return None;
}
let new_elements = Vec::with_capacity(self.elements.len());
let result = std::mem::replace(&mut self.elements, new_elements);
self.refill(result.len());
Some(result)
}
}
fn main() {
let v = vec!(1, 2, 3, 4, 5);
for slice in Chunks::new(v.iter(), 2) {
println!("{:?}", slice);
}
}
返回结果:
[1, 2] [3, 4] [5]
这个精明的读者会发现,我偷偷从windows
切换到chunks
。
windows
更困难,因为它多次返回相同的元素,要求元素为Clone
。此外,由于每次需要返回完整Vec
,因此需要在内部保留Vec<Vec<Iterator::Item>>
。
这是作为练习留给读者。
最后,性能一张纸条:所有分配是会受到伤害(尤其是在windows
的情况下)。
最好的分配策略通常是分配一块内存,然后靠它(除非数量真的很大,在这种情况下需要流式传输)。
它在Rust中被称为collect::<Vec<_>>()
。
而且由于Vec
有chunks
和windows
方法(由于实施Deref<Target=[T]>
的),你就可以使用,而不是:
for slice in v.iter().collect::<Vec<_>>().chunks(2) {
println!("{:?}", slice);
}
for slice in v.iter().collect::<Vec<_>>().windows(2) {
println!("{:?}", slice);
}
有时候最好的解决方案是最简单的。
对不起,downvote,但*所要求的确切语法是不可能在锈*是不正确的;请检查[我的答案](http://stackoverflow.com/a/42139758/155423)。但其余的大部分分析都很有意义。 – Shepmaster
@Shepmaster:你的答案没有要求的确切语法。在some_iter.windows(2)'中,这个请求是'for(prev,next)',其中有一个运行时参数,我认为这意味着我可以传递3并且在for_iter.windows中有for(n0,n1,n2) (3)'那是不可能的。你选择专注于'(prev,next)'并且忽略运行时参数,它可能与OP一致,但就我而言,这不是他们所要求的(我并没有阅读意见)。 –
好点。指定* both *元组的大小和'windows'的参数都没有意义,特别是如果有不匹配的话。我可能会鼓励你在你的回答中明确地注意到这一点 - 可能会增加一个例子? – Shepmaster
这是可能的使用Itertools::tuples
,由4元组取一个迭代的块:
extern crate itertools;
use itertools::Itertools;
fn main() {
let some_iter = vec![1, 2, 3, 4, 5, 6].into_iter();
for (prev, next) in some_iter.tuples() {
println!("{}--{}", prev, next);
}
}
1--2
3--4
5--6
除了最多4元组的窗口与Itertools::tuple_windows
:
extern crate itertools;
use itertools::Itertools;
fn main() {
let some_iter = vec![1, 2, 3, 4, 5, 6].into_iter();
for (prev, next) in some_iter.tuple_windows() {
println!("{}--{}", prev, next);
}
}
1--2
2--3
3--4
4--5
5--6
它可以与3元素的元组一起工作吗?看看这个文档,看起来它可能是可能的。 –
@MatthieuM。是的,但实现的数量*仅限于一个4元组(我已经添加)。 – Shepmaster
是的,呃......在没有可变参数的情况下,实现它我觉得很痛苦(而且体积太大)。 –
你可以很容易地做一个'iter_pairs','iter_triples'一旦你决定做什么,如果没有足够的项目在年底,而不是一个通用的“任何规模大小元组”一个有锈此时此刻。 –
如果没有足够的功能,它将不会执行任何操作,例如切片功能。 – ideasman42
这在IRC https://docs.rs/itertools/*/ itertools/trait.Itertools.html#method.tuple_windows'想指向我,并希望在发布答案之前查看它的代码。 – ideasman42