I understand that the preferred way to iterate in Rust is through the for var in (range)
syntax, but sometimes I'd like to work on more than one of the elements in that range at a time.
From a Ruby perspective, I'm trying to find a way of doing (1..100).each_slice(5) do |this_slice|
in Rust.
I'm trying things like
for mut segment_start in (segment_size..max_val).step_by(segment_size) {
let this_segment = segment_start..(segment_start + segment_size).iter().take(segment_size);
}
but I keep getting errors that suggest I'm barking up the wrong type tree. The docs aren't helpful either--they just don't contain this use case.
What's the Rust way to do this?
Rust - Slices 1 Syntax. The minimum index value is 0 and the maximum index value is the size of the data structure. NOTE that the end_index will not be included in final string. 2 Output 3 Illustration - Slicing an integer array. The main () function declares an array with 5 elements. ...
Slices are also present in Python which is similar to slice here in Rust. Slice is used when you do not want the complete collection, or you want some part of it. In slicing first element is at 0 index and the last is index-1. //gfg is String or Array &gfg [0..2] //from 0 to 1 index &gfg [0..3] //from 0 to 2 index
In Rust, an array's size is part of the type. For example, this code will not compile: Rust's strictness also prevents problems like array to pointer decay in C/C++: //C++ code #include <iostream> using namespace std; //Looks can be deceiving: arr is not a pointer //to an array of 5 integers.
For example if you have an array: You can create a slice containing second and third elements like this: The [1..3] syntax creates a range from index 1 (inclusive) to 3 (exclusive). If you omit the first number in the range ( [..3]) it defaults to zero and if you omit the last number ( [1..]) it defaults to the length of the array.
Use chunks
(or chunks_mut
if you need mutability):
fn main() {
let things = [5, 4, 3, 2, 1];
for slice in things.chunks(2) {
println!("{:?}", slice);
}
}
Outputs:
[5, 4]
[3, 2]
[1]
The easiest way to combine this with a Range
would be to collect the range to a Vec
first (which dereferences to a slice):
fn main() {
let things: Vec<_> = (1..100).collect();
for slice in things.chunks(5) {
println!("{:?}", slice);
}
}
Another solution that is pure-iterator would be to use Itertools::chunks_lazy
:
extern crate itertools;
use itertools::Itertools;
fn main() {
for chunk in &(1..100).chunks_lazy(5) {
for val in chunk {
print!("{}, ", val);
}
println!("");
}
}
Which suggests a similar solution that only requires the standard library:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
for value in range.by_ref().take(5) {
print!("{}, ", value);
}
println!("");
}
}
One trick is that Ruby and Rust have different handling here, mostly centered around efficiency.
In Ruby Enumerable
can create new arrays to stuff values in without worrying about ownership and return a new array each time (check with this_slice.object_id
).
In Rust, allocating a new vector each time would be pretty unusual. Additionally, you can't easily return a reference to a vector that the iterator holds due to complicated lifetime concerns.
A solution that's very similar to Ruby's is:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
let chunk: Vec<_> = range.by_ref().take(5).collect();
println!("{:?}", chunk);
}
}
Which could be wrapped up in a new iterator that hides the details:
use std::iter::Peekable;
struct InefficientChunks<I>
where I: Iterator
{
iter: Peekable<I>,
size: usize,
}
impl<I> Iterator for InefficientChunks<I>
where I: Iterator
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.iter.peek().is_some() {
Some(self.iter.by_ref().take(self.size).collect())
} else {
None
}
}
}
trait Awesome: Iterator + Sized {
fn inefficient_chunks(self, size: usize) -> InefficientChunks<Self> {
InefficientChunks {
iter: self.peekable(),
size: size,
}
}
}
impl<I> Awesome for I where I: Iterator {}
fn main() {
for chunk in (1..100).inefficient_chunks(5) {
println!("{:?}", chunk);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With