๐Ÿฆ€ Functional Rust
๐ŸŽฌ Error Handling in Rust Option, Result, the ? operator, and combinators.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Option represents a value that may or may not exist โ€” Some(value) or None

โ€ข Result represents success (Ok) or failure (Err) โ€” no exceptions needed

โ€ข The ? operator propagates errors up the call stack concisely

โ€ข Combinators like .map(), .and_then(), .unwrap_or() chain fallible operations

โ€ข The compiler forces you to handle every error case โ€” no silent failures

016: Drop Every Nth

Difficulty: 1 Level: Foundations Remove every nth element from a list โ€” keeping all the rest.

The Problem This Solves

Imagine you're sampling audio data and need to downsample by removing every 3rd measurement. Or you're paginating records and want to discard every nth row as a separator. The task: given `['a','b','c','d','e','f','g','h','i','k']` and `n=3`, produce `['a','b','d','e','g','h','k']` โ€” dropping positions 3, 6, 9. In Python you might write a list comprehension: `[x for i, x in enumerate(lst, 1) if i % n != 0]`. That works, but it's ad-hoc โ€” every team member writes it slightly differently, and nothing stops you from making an off-by-one error silently. Rust's iterator approach does the same thing with named, composable steps. The compiler checks types at every stage, and the code reads almost like a sentence: enumerate the list, filter out every nth position, collect the values.

The Intuition

In Python: `[x for i, x in enumerate(lst, 1) if i % n != 0]` In JavaScript: `lst.filter((_, i) => (i + 1) % n !== 0)` In Rust, iterators work the same way โ€” they're lazy chains that transform data step by step. The key method here is `.enumerate()`, which gives you `(index, value)` pairs, then `.filter()` to keep only what you want, then `.map()` to peel off the index again. One important detail: Rust indices are 0-based, but this problem uses 1-based counting ("every 3rd" means positions 1, 2, 3, 4, 5, 6โ€ฆ). That's why the filter checks `(i + 1) % n != 0`.

How It Works in Rust

fn drop_every<T: Clone>(lst: &[T], n: usize) -> Vec<T> {
 if n == 0 {
     return lst.to_vec(); // edge case: no-op
 }
 lst.iter()
     .enumerate()           // (0,'a'), (1,'b'), (2,'c'), ...
     .filter(|(i, _)| (i + 1) % n != 0)  // keep if NOT a multiple of n
     .map(|(_, x)| x.clone())             // discard the index
     .collect()             // gather into Vec<T>
}
The `T: Clone` bound means "T must be copyable" โ€” needed because we're extracting values from a reference into a new owned `Vec`. For simple types like `char` or `i32`, this is trivially cheap. There's also a recursive version in the code (`drop_every_rec`) that mirrors the OCaml style: pattern-match on the list, count down to n, drop that element, reset the counter. Both produce identical results โ€” the iterator version is more idiomatic Rust.

What This Unlocks

Key Differences

ConceptOCamlRust
Enumerate`List.mapi (fun i x -> (i, x))``.enumerate()` on any iterator
Filter by indexList comprehension / recursive`.filter((i, _)` โ†’ condition`)`
1-based indexExplicit counter in recursion`(i + 1)` offset in filter
Result type`'a list``Vec<T>` (owned, heap-allocated)
Edge case (n=0)Guard in pattern matchEarly `return` before iterator chain
// Drop Every Nth Element โ€” 99 Problems #16
// Drop every nth element from a list.
// drop_every ['a','b','c','d','e','f','g','h','i','k'] 3
//   โ†’ ['a','b','d','e','g','h','k']

fn drop_every<T: Clone>(lst: &[T], n: usize) -> Vec<T> {
    if n == 0 {
        return lst.to_vec();
    }
    lst.iter()
        .enumerate()
        .filter(|(i, _)| (i + 1) % n != 0)
        .map(|(_, x)| x.clone())
        .collect()
}

/// Recursive version matching OCaml style.
fn drop_every_rec<T: Clone>(lst: &[T], n: usize) -> Vec<T> {
    fn aux<T: Clone>(lst: &[T], n: usize, count: usize) -> Vec<T> {
        match lst {
            [] => vec![],
            [head, tail @ ..] => {
                if count == n {
                    aux(tail, n, 1)
                } else {
                    let mut result = vec![head.clone()];
                    result.extend(aux(tail, n, count + 1));
                    result
                }
            }
        }
    }
    aux(lst, n, 1)
}

fn main() {
    let input = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
    println!("Input:           {:?}", input);
    println!("Drop every 3rd:  {:?}", drop_every(&input, 3));
    println!("Drop every 2nd:  {:?}", drop_every(&input, 2));
    println!("Drop every 1st:  {:?}", drop_every(&input, 1));
    println!("Rec every 3rd:   {:?}", drop_every_rec(&input, 3));
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_drop_every_3rd() {
        let input = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
        assert_eq!(
            drop_every(&input, 3),
            vec!['a', 'b', 'd', 'e', 'g', 'h', 'k']
        );
    }

    #[test]
    fn test_drop_every_1st() {
        // Drop every 1st = drop all
        assert_eq!(drop_every(&[1, 2, 3], 1), vec![]);
    }

    #[test]
    fn test_drop_every_larger_than_list() {
        // n > length: nothing dropped
        assert_eq!(drop_every(&[1, 2, 3], 5), vec![1, 2, 3]);
    }

    #[test]
    fn test_recursive_matches_iter() {
        let input = vec!['a', 'b', 'c', 'd', 'e', 'f'];
        assert_eq!(drop_every(&input, 3), drop_every_rec(&input, 3));
    }
}
(* Drop Every Nth *)
(* OCaml 99 Problems #16 *)

(* Implementation for example 16 *)

(* Tests *)
let () =
  (* Add tests *)
  print_endline "โœ“ OCaml tests passed"