ExamplesBy LevelBy TopicLearning Paths
262 Intermediate

262: Sliding Windows over Slices

Functional Programming

Tutorial

The Problem

Signal processing, time-series analysis, and pattern recognition algorithms frequently examine overlapping subsequences of fixed length. A moving average over stock prices, an n-gram language model, or detecting whether an array is sorted — all require looking at consecutive groups of elements simultaneously. The windows(n) method provides zero-copy, overlapping sub-slices of a fixed length, making these algorithms expressible as simple iterator pipelines.

🎯 Learning Outcomes

  • • Understand how windows(n) yields overlapping sub-slices of length n
  • • Distinguish windows() from chunks(): overlapping vs non-overlapping
  • • Compute sliding averages, detect sorted order, and find patterns using windows()
  • • Recognize the zero-copy nature: each window is a borrowed sub-slice, not a new allocation
  • Code Example

    #![allow(clippy::all)]
    //! 262. Sliding windows over slices
    //!
    //! `windows(n)` yields overlapping sub-slices of length `n`, zero-copy.
    
    #[cfg(test)]
    mod tests {
        #[test]
        fn test_windows_count() {
            let data = [1i32, 2, 3, 4, 5];
            assert_eq!(data.windows(3).count(), 3);
        }
    
        #[test]
        fn test_windows_moving_avg() {
            let data = [1i32, 2, 3, 4, 5];
            let avgs: Vec<f64> = data
                .windows(2)
                .map(|w| w.iter().sum::<i32>() as f64 / 2.0)
                .collect();
            assert_eq!(avgs, vec![1.5, 2.5, 3.5, 4.5]);
        }
    
        #[test]
        fn test_windows_sorted_check() {
            let sorted = [1i32, 2, 3, 4];
            assert!(sorted.windows(2).all(|w| w[0] <= w[1]));
            let unsorted = [1i32, 3, 2, 4];
            assert!(!unsorted.windows(2).all(|w| w[0] <= w[1]));
        }
    }

    Key Differences

  • Zero-copy: Rust's windows() yields borrowed &[T] slices with no allocation; OCaml's equivalent creates new sub-lists.
  • Overlap: windows(n) is overlapping; chunks(n) is non-overlapping — two complementary methods in Rust.
  • Standard library: windows() is a stable part of Rust's slice API; OCaml requires user-defined functions.
  • Use cases: Signal processing (DSP), n-gram text analysis, financial moving averages, sorted-order detection.
  • OCaml Approach

    OCaml lacks a standard windows function on lists. The idiomatic functional approach uses List.init and List.sub on arrays, or defines a recursive function that takes the head as a sub-list:

    let windows n lst =
      let arr = Array.of_list lst in
      Array.init (Array.length arr - n + 1) (fun i ->
        Array.to_list (Array.sub arr i n))
    

    This allocates new sub-arrays; Rust's windows() avoids this via slice references.

    Full Source

    #![allow(clippy::all)]
    //! 262. Sliding windows over slices
    //!
    //! `windows(n)` yields overlapping sub-slices of length `n`, zero-copy.
    
    #[cfg(test)]
    mod tests {
        #[test]
        fn test_windows_count() {
            let data = [1i32, 2, 3, 4, 5];
            assert_eq!(data.windows(3).count(), 3);
        }
    
        #[test]
        fn test_windows_moving_avg() {
            let data = [1i32, 2, 3, 4, 5];
            let avgs: Vec<f64> = data
                .windows(2)
                .map(|w| w.iter().sum::<i32>() as f64 / 2.0)
                .collect();
            assert_eq!(avgs, vec![1.5, 2.5, 3.5, 4.5]);
        }
    
        #[test]
        fn test_windows_sorted_check() {
            let sorted = [1i32, 2, 3, 4];
            assert!(sorted.windows(2).all(|w| w[0] <= w[1]));
            let unsorted = [1i32, 3, 2, 4];
            assert!(!unsorted.windows(2).all(|w| w[0] <= w[1]));
        }
    }
    ✓ Tests Rust test suite
    #[cfg(test)]
    mod tests {
        #[test]
        fn test_windows_count() {
            let data = [1i32, 2, 3, 4, 5];
            assert_eq!(data.windows(3).count(), 3);
        }
    
        #[test]
        fn test_windows_moving_avg() {
            let data = [1i32, 2, 3, 4, 5];
            let avgs: Vec<f64> = data
                .windows(2)
                .map(|w| w.iter().sum::<i32>() as f64 / 2.0)
                .collect();
            assert_eq!(avgs, vec![1.5, 2.5, 3.5, 4.5]);
        }
    
        #[test]
        fn test_windows_sorted_check() {
            let sorted = [1i32, 2, 3, 4];
            assert!(sorted.windows(2).all(|w| w[0] <= w[1]));
            let unsorted = [1i32, 3, 2, 4];
            assert!(!unsorted.windows(2).all(|w| w[0] <= w[1]));
        }
    }

    Exercises

  • Use windows(3) to compute a 3-element moving average over a Vec<f64> of temperature readings.
  • Detect local maxima in a sequence: an element is a local maximum if it is strictly greater than its neighbors — use windows(3).
  • Find the starting index of a pattern (sub-slice) within a larger slice using windows() and position().
  • Open Source Repos