๐Ÿฆ€ Functional Rust
๐ŸŽฌ How Rust Iterators Work Lazy evaluation, chaining, collect(), and zero-cost abstractions.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Iterators are lazy โ€” .map(), .filter(), .take() build a chain but do no work until consumed

โ€ข .collect() triggers evaluation, transforming the chain into a Vec, HashMap, or other collection

โ€ข Zero-cost abstraction: iterator chains compile to the same machine code as hand-written loops

โ€ข .iter() borrows, .into_iter() consumes, .iter_mut() borrows mutably

โ€ข Chaining replaces nested loops with a readable, composable pipeline

266: Iterator step_by()

Difficulty: 1 Level: Beginner Stride through an iterator, yielding every nth element โ€” lazy, zero-allocation, works on infinite sequences.

The Problem This Solves

You want every third element from a list, or multiples of 5 from a range, or to downsample a signal array. Without `step_by`, you'd write a counter variable, manually increment it, and check `if counter % n == 0` โ€” imperative noise for a declarative idea. Or you'd reach for `filter(|i| i % n == 0)` on an enumerated iterator, which is verbose and less readable. `step_by(n)` names the intent directly: "give me every nth element." It's lazy (no intermediate allocation), works on any iterator including infinite ones, and composes with the rest of the iterator pipeline. For downsampling audio, generating arithmetic sequences, or accessing every kth row of a matrix, it's the idiomatic choice. A common gotcha: `step_by(1)` is identity โ€” it yields every element. `step_by(0)` panics.

The Intuition

Yield the first element, skip n-1, yield the next, skip n-1, repeat โ€” effectively striding through the iterator at a fixed interval.

How It Works in Rust

// Every 3rd element from a range
let thirds: Vec<usize> = (0..10).step_by(3).collect();
// โ†’ [0, 3, 6, 9]

// Arithmetic sequences from infinite iterator
let odd_positions: Vec<u64> = (1u64..).step_by(2).take(5).collect();
// โ†’ [1, 3, 5, 7, 9]

// Downsample a signal array
let signal = [1.0f64, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let downsampled: Vec<f64> = signal.iter().copied().step_by(2).collect();
// โ†’ [1.0, 3.0, 5.0, 7.0]

// Every other character
let every_other: String = "abcdefgh".chars().step_by(2).collect();
// โ†’ "aceg"
The key: `step_by` takes n as the stride, starting from index 0. It does not skip the first element.

What This Unlocks

Key Differences

ConceptOCamlRust
Equivalent`List.filteri (fun i _ -> i mod n = 0) lst``iter.step_by(n)`
LazyNo (lists are eager)Yes
Infinite sequencesNoYes (with `(0..).step_by(n)`)
ReadabilityVerbose (index + modulo)Declarative
Zero-copyNo (new list)Yes (adapter over original)
//! 266. Striding with step_by()
//!
//! `step_by(n)` yields every nth element โ€” the first, then skips n-1, and so on.

fn main() {
    let thirds: Vec<usize> = (0..10).step_by(3).collect();
    println!("Every 3rd (0..10): {:?}", thirds);

    let mult5: Vec<i32> = (0..=50).step_by(5).collect();
    println!("Multiples of 5: {:?}", mult5);

    let signal = [1.0f64, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
    let downsampled: Vec<f64> = signal.iter().copied().step_by(2).collect();
    println!("Downsampled: {:?}", downsampled);

    let s = "abcdefgh";
    let every_other: String = s.chars().step_by(2).collect();
    println!("Every other char: {}", every_other);

    // Infinite sequence striding
    let odd_positions: Vec<u64> = (1u64..).step_by(2).take(5).collect();
    println!("Odd positions: {:?}", odd_positions);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_step_by_3() {
        let result: Vec<usize> = (0..10).step_by(3).collect();
        assert_eq!(result, vec![0, 3, 6, 9]);
    }

    #[test]
    fn test_step_by_2() {
        let result: Vec<i32> = [1, 2, 3, 4, 5].iter().copied().step_by(2).collect();
        assert_eq!(result, vec![1, 3, 5]);
    }

    #[test]
    fn test_step_by_1_identity() {
        let result: Vec<i32> = (1..=4).step_by(1).collect();
        assert_eq!(result, vec![1, 2, 3, 4]);
    }

    #[test]
    fn test_step_by_multiples() {
        let result: Vec<i32> = (0..=20).step_by(5).collect();
        assert_eq!(result, vec![0, 5, 10, 15, 20]);
    }
}
(* 266. Striding with step_by() - OCaml *)

let step_by n lst = List.filteri (fun i _ -> i mod n = 0) lst

let () =
  let nums = List.init 10 Fun.id in
  let thirds = step_by 3 nums in
  Printf.printf "Every 3rd: %s\n"
    (String.concat ", " (List.map string_of_int thirds));

  let mult_5 = step_by 5 (List.init 51 Fun.id) in
  Printf.printf "Multiples of 5: %s\n"
    (String.concat ", " (List.map string_of_int mult_5));

  let s = "abcdefgh" in
  let chars = List.init (String.length s) (fun i -> s.[i]) in
  let every_other = step_by 2 chars in
  Printf.printf "Every other char: %s\n"
    (String.concat "" (List.map (String.make 1) every_other))