patternrustModerate
Are there equivalents to slice::chunks/windows for iterators to loop over pairs, triplets etc?
Viewed 0 times
equivalentsslicechunksareiteratorspairsoverfortripletsloop
Problem
It can be useful to iterate over multiple variables at once, overlapping (
This only works for slices; is it possible to do this for iterators, using tuples for convenience?
Something like the following could be written:
If not, could it be implemented as a trait on existing iterators?
slice::windows), or not (slice::chunks).This only works for slices; is it possible to do this for iterators, using tuples for convenience?
Something like the following could be written:
for (prev, next) in some_iter.windows(2) {
...
}If not, could it be implemented as a trait on existing iterators?
Solution
On stable
Since Rust 1.51 this is possible with const generics where the iterator yields constant size arrays
I built the
Using the example given in the
This outputs
Most times the array size can be inferred but you can also specific it explicitly. Additionally, any reasonable size
This outputs
Note:
On nightly
The chunks version is now available on nightly under the name
And it handles remainders nicely:
Performance
The iterator versions are particularly useful if you are not iterating over some contiguous collection. However, depending on your use-case you might find that collecting into a
Since Rust 1.51 this is possible with const generics where the iterator yields constant size arrays
[T; N] for any N.I built the
itermore crate which implements both of these, providing the array_chunks() and array_windows() methods under separate extension traits.use itermore::IterArrayChunks; // 0.7
for [a, b, c] in some_iter.by_ref().array_chunks() {
...
}
let rem = some_iter.into_remainder();
use itermore::IterArrayWindows; // 0.7
for [prev, next] in some_iter.array_windows() {
...
}
Using the example given in the
Itertools answer:use itermore::IterArrayChunks; // 0.7
fn main() {
let some_iter = vec![1, 2, 3, 4, 5, 6].into_iter();
for [prev, next] in some_iter.array_chunks() {
println!("{}--{}", prev, next);
}
}This outputs
1--2
3--4
5--6Most times the array size can be inferred but you can also specific it explicitly. Additionally, any reasonable size
N can be used, there is no limit like in the Itertools case.use itermore::IterArrayWindows; // 0.7
fn main() {
let mut iter = vec![1, 2, 3, 4, 5, 6].into_iter().array_windows::();
println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());
}
This outputs
Some([1, 2, 3, 4, 5])
Some([2, 3, 4, 5, 6])
NoneNote:
array_windows() uses clone to yield elements multiple times so its best used for references and cheap to copy types.On nightly
The chunks version is now available on nightly under the name
array_chunks#![feature(iter_array_chunks)]
for [a, b, c] in some_iter.array_chunks() {
...
}And it handles remainders nicely:
#![feature(iter_array_chunks)]
for [a, b, c] in some_iter.by_ref().array_chunks() {
...
}
let rem = some_iter.into_remainder();Performance
The iterator versions are particularly useful if you are not iterating over some contiguous collection. However, depending on your use-case you might find that collecting into a
Vec first and using the slice methods might be faster even including the time allocate the iterator into a Vec. This is particularly true in the case of array_windows where the elements need to be cloned.Code Snippets
use itermore::IterArrayChunks; // 0.7
fn main() {
let some_iter = vec![1, 2, 3, 4, 5, 6].into_iter();
for [prev, next] in some_iter.array_chunks() {
println!("{}--{}", prev, next);
}
}1--2
3--4
5--6Some([1, 2, 3, 4, 5])
Some([2, 3, 4, 5, 6])
None#![feature(iter_array_chunks)]
for [a, b, c] in some_iter.array_chunks() {
...
}#![feature(iter_array_chunks)]
for [a, b, c] in some_iter.by_ref().array_chunks() {
...
}
let rem = some_iter.into_remainder();Context
Stack Overflow Q#42134874, score: 20
Revisions (0)
No revisions yet.