一次迭代多個變量可能很有用,重疊(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