skip, take Examples
This page was last reviewed on Jan 29, 2023.
Dot Net Perls
Skip, take. In Rust we can use the skip and take functions to advance to a position in an iterator. The clippy tool recommends skip and take.
With these functions, we narrow down the range of an iter(). We usually need to call iter() first to use skip and take. These functions affect loop performance.
Skip example. To begin, we create an array of 4 numbers. We get an iterator from the array by calling iter() in the for-loop. We print out the values looped over.
And We call skip() with an argument of 2 on the return value of iter(). This skips over 2 elements from the start.
Result When we call skip() with an argument of 2, we access just the third and fourth elements, 30 and 40.
fn main() { // Source array. let values = [10, 20, 30, 40]; // Loop starting past the first 2 items. for value in values.iter().skip(2) { println!("SKIP 2 FROM {:?} = {}", values, value); } }
SKIP 2 FROM [10, 20, 30, 40] = 30 SKIP 2 FROM [10, 20, 30, 40] = 40
Take. With take() we iterate over the first elements of a collection like an array. We specify the number of elements we wish to loop over.
Here We combine skip and take. This allows us to loop over only some of the middle elements in an array.
fn main() { let numbers = [5, 10, 20, 40]; // Loop over first 2 numbers. for number in numbers.iter().take(2) { println!("TAKE 2: {number}"); } // Combine skip and take. for number in numbers.iter().skip(1).take(2) { println!("SKIP 1 TAKE 2: {number}"); } }
TAKE 2: 5 TAKE 2: 10 SKIP 1 TAKE 2: 10 SKIP 1 TAKE 2: 20
Skip benchmark. The clippy tool recommends using skip and take instead of for-range loops. But does this improve performance? We test skip and take performance here.
Version 1 This version of the code uses a for-loop over a range of indexes. It then tests the vector elements.
Version 2 This code uses a for-loop but uses skip and take instead of a range of indexes. It has the same effect as version 1.
Result Using skip() and take() on a loop seems to reduce performance. Just accessing indexes directly is faster.
use std::time::*; fn main() { if let Ok(max) = "20000".parse() { if let Ok(offset) = "20".parse::<usize>() { let top_offset = max - offset; // Sample vector. let mut source = vec![]; for _ in 0..max { source.push(0); } source[5000] = 1; let mut sum1 = 0; let mut sum2 = 0; // Version 1: range loop. let t0 = Instant::now(); for _ in 0..max { for i in offset..top_offset { if source[i] == 1 { sum1 += 1; } } } println!("{}", t0.elapsed().as_millis()); // Version 2: take and skip. let t1 = Instant::now(); for _ in 0..max { for element in source.iter().take(top_offset).skip(offset) { if *element == 1 { sum2 += 1; } } } println!("{}", t1.elapsed().as_millis()); println!("{} = {}", sum1, sum2); } } }
222 249 20000 = 20000
Loop optimization. In my tests, using skip and take with iter() is slower than accessing indexes from a range directly. And using get_unchecked with a range is the fastest approach.
get unchecked
A summary. A main goal of using Rust is to achieve excellent performance. With skip and take, we can narrow down a loop in a safe way. But unsafe code, and direct index accesses, may be faster.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Jan 29, 2023 (new example).
© 2007-2024 Sam Allen.