022: Range
Difficulty: 1 Level: Foundations Create a list of all integers between two values โ ascending or descending.The Problem This Solves
Generating integer sequences is one of the most basic programming tasks: page numbers, loop indices, test data, coordinate grids. Given `start=4` and `end=9`, produce `[4, 5, 6, 7, 8, 9]`. If `start > end`, produce the reverse: `[9, 8, 7, 6, 5, 4]`. Python has `range(4, 10)` built in, and JavaScript uses `Array.from({length: n}, (_, i) => start + i)`. These are fine but don't auto-detect direction โ you need `range(9, 3, -1)` for descending in Python, or a separate implementation. Rust's range syntax `(start..=end).collect()` is native and zero-cost โ it generates values lazily and collects into a `Vec` only when needed. Adding direction detection is two lines. And since Rust's ranges are typed, the compiler catches mixing `i32` and `usize` before they cause bugs.The Intuition
In Python: `list(range(4, 10))` (ascending) or `list(range(9, 3, -1))` (descending) In JavaScript: `Array.from({length: end - start + 1}, (_, i) => start + i)` Rust uses the `..=` syntax for inclusive ranges (both ends included). `(4..=9)` creates a `RangeInclusive<i64>` iterator. Calling `.collect()` on it gathers all values into a `Vec<i64>`. For descending ranges, Rust's `(end..=start).rev()` reverses the iteration. The function detects which direction to use based on `start <= end`.How It Works in Rust
fn range(start: i64, end: i64) -> Vec<i64> {
if start <= end {
(start..=end).collect() // ascending: 4, 5, 6, 7, 8, 9
} else {
(end..=start).rev().collect() // descending: 9, 8, 7, 6, 5, 4
}
}
- `start..=end` โ inclusive range (both endpoints included)
- `.collect()` โ turns the lazy iterator into a `Vec<i64>`
- `.rev()` โ reverses iteration direction; no extra allocation needed
- The type `Vec<i64>` is inferred from context
What This Unlocks
- Test data generation โ create input sequences without hardcoding arrays.
- Coordinate grids โ `range(0, width)` and `range(0, height)` for 2D iteration.
- Index sequences โ generate valid indices to use in other slice operations.
Key Differences
| Concept | OCaml | Rust |
|---|---|---|
| Built-in range | `List.init n (fun i -> start + i)` | `(start..=end).collect()` |
| Inclusive range | Manual: `start..end+1` in `List.init` | `..=` is inclusive on both ends |
| Descending | Requires `List.rev` or negative step | `(end..=start).rev().collect()` |
| Lazy evaluation | Evaluated eagerly in list form | `Range` is lazy; `.collect()` forces it |
| Step size | Custom recursive function | `.map()` + `.take_while()` chain |
// Range โ 99 Problems #22
// Create a list containing all integers in a given range.
// range 4 9 โ [4, 5, 6, 7, 8, 9]
fn range(start: i64, end: i64) -> Vec<i64> {
if start <= end {
(start..=end).collect()
} else {
(end..=start).rev().collect()
}
}
/// Recursive version.
fn range_rec(start: i64, end: i64) -> Vec<i64> {
if start > end {
vec![]
} else {
let mut result = vec![start];
result.extend(range_rec(start + 1, end));
result
}
}
/// Using Iterator::step_by for arbitrary step (generalized).
fn range_step(start: i64, end: i64, step: i64) -> Vec<i64> {
let step = if step == 0 { 1 } else { step.abs() };
if start <= end {
(0..)
.map(|i| start + i * step)
.take_while(|&x| x <= end)
.collect()
} else {
(0..)
.map(|i| start - i * step)
.take_while(|&x| x >= end)
.collect()
}
}
fn main() {
println!("range(4, 9): {:?}", range(4, 9));
println!("range(9, 4): {:?}", range(9, 4));
println!("range(5, 5): {:?}", range(5, 5));
println!("range(-3, 3): {:?}", range(-3, 3));
println!("range_rec(1, 5): {:?}", range_rec(1, 5));
println!("step(0, 10, 2): {:?}", range_step(0, 10, 2));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_range_ascending() {
assert_eq!(range(4, 9), vec![4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_range_descending() {
assert_eq!(range(9, 4), vec![9, 8, 7, 6, 5, 4]);
}
#[test]
fn test_range_single() {
assert_eq!(range(5, 5), vec![5]);
}
#[test]
fn test_range_rec_matches() {
assert_eq!(range(1, 5), range_rec(1, 5));
}
#[test]
fn test_range_negative() {
assert_eq!(range(-3, 0), vec![-3, -2, -1, 0]);
}
}
(* Range *)
(* OCaml 99 Problems #22 *)
(* Implementation for example 22 *)
(* Tests *)
let () =
(* Add tests *)
print_endline "โ OCaml tests passed"