use itertools::Itertools; // 0.9.0
fn main() {
let some_iter = vec![1, 2, 3, 4, 5].into_iter();
let mut t = some_iter.tuples();
for (prev, next) in t.by_ref() {
println!("{}--{}", prev, next);
}
for leftover in t.into_buffer() {
println!("{}", leftover);
}
}
for slice in v.iter().collect::<Vec<_>>().chunks(2) {
println!("{:?}", slice);
}
for slice in v.iter().collect::<Vec<_>>().windows(2) {
println!("{:?}", slice);
}
3条答案
按热度按时间dxpyg8gm1#
可以使用
Itertools::tuples
获取迭代器的块,最多可以获取4元组:(playground)(英文)
如果不知道迭代器是否完全适合块,可以使用
Tuples::into_buffer
来访问剩余部分:(playground)
也可以使用
Itertools::tuple_windows
来获取最多4元组窗口:(playground)
如果需要获取部分块/窗口,可以获取
55ooxyrt2#
TL;DR:在任意迭代器/集合上拥有
chunks
和windows
的最好方法是首先将collect
转换为Vec
,然后在 * 该 * 上迭代。在Rust中不可能实现所请求的精确语法。
问题在于,在Rust中,函数的签名依赖于 * 类型 *,而不是 * 值 *,尽管存在依赖类型,但很少有语言实现它(这很难)。
这就是为什么
chunks
和windows
顺便返回子切片的原因;&[T]
中的元素数量不是类型的一部分,因此可以在运行时确定。让我们假设您要求:而不是
for slice in some_iter.windows(2)
。支持此切片的存储将位于何处?
它不能生存:
LinkedList
没有连续的存储空间Iterator::Item
的定义,没有可用的生存期因此,遗憾的是,只有当后备存储是片时才能使用片。
如果接受动态分配,则可以使用
Vec<Iterator::Item>
作为分块迭代器的Item
。将返回:
精明的读者会意识到我偷偷地从
windows
切换到chunks
。windows
比较困难,因为它会多次返回相同的元素,这就要求该元素必须是Clone
。此外,由于它每次都需要返回完整的Vec
,因此它需要在内部保留一个Vec<Vec<Iterator::Item>>
。这是留给读者的练习。
最后,关于性能的注意事项:所有这些分配都是有害的(特别是在
windows
的情况下)。最好的分配策略通常是分配一个内存块,然后靠它生存(除非内存量非常大,在这种情况下需要流)。
在Rust中它被称为
collect::<Vec<_>>()
。由于
Vec
有chunks
和windows
方法(通过实现Deref<Target=[T]>
),因此可以使用该方法:有时候最好的解决方案就是最简单的。
s5a0g9ez3#
每晚
chunks版本现在每晚在上可用,名称为
array_chunks
它还能很好地处理余数:
在马厩
从Rust 1.51开始,这可以通过const泛型实现,其中迭代器为任何
N
生成常量大小的数组**[T; N]
**。我构建了两个独立的板条箱来实现这一点:
iterchunks
提供chunks()
iterwindows
提供windows()
第一次
使用
Itertools
答案中给出的示例:此输出
大多数情况下,数组的大小是可以推断的,但是你也可以明确地指定它。另外,可以使用任何合理的大小
N
,没有像Itertools
那样的限制。此输出
注意:
windows()
使用clone来多次生成元素,因此它最好用于引用,并且复制类型的成本较低。