024 — Lotto — Draw N Different Random Numbers from the Set 1..M
Tutorial Video
Text description (accessibility)
This video demonstrates the "024 — Lotto — Draw N Different Random Numbers from the Set 1..M" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. A lotto draw selects k distinct numbers from 1 to m uniformly at random — for example, a 6/49 lottery draws 6 numbers from {1, ..., 49}. Key difference from OCaml: 1. **Reuse vs inline**: OCaml composes `range` (problem 22) + `random_select` (problem 23). Rust can do the same or use the built
Tutorial
The Problem
A lotto draw selects k distinct numbers from 1 to m uniformly at random — for example, a 6/49 lottery draws 6 numbers from {1, ..., 49}. This is random selection without replacement from a generated range, combining examples 022 (range) and 023 (random select) into a single operation.
The problem appears in lottery systems, statistical sampling, hash table probing sequences (linear probing with random start), cryptographic nonce generation, and randomized algorithms like random QuickSort pivot selection. Understanding that "random draw from 1..m" is equivalent to "shuffle range(1, m+1), take first k" is the key insight.
🎯 Learning Outcomes
[1..=m], shuffle it, and take the first k elementsVec::shuffle from the rand::seq::SliceRandom traitrange(1..=m) and random_select(k) to implement lotto as a reuse of previously solved problemsCode Example
#![allow(clippy::all)]
// Placeholder — pending conversionKey Differences
range (problem 22) + random_select (problem 23). Rust can do the same or use the built-in shuffle which is more efficient on Vec.shuffle vs choose_multiple**: Vec::shuffle rearranges all m elements (O(m)). choose_multiple uses a selection algorithm and is O(k) when k << m. For k=6, m=49 both are fast; for k=6, m=1_000_000 choose_multiple wins.result.sort(). OCaml: List.sort compare result. Both are O(k log k) after selection.HashSet but is better for sparse k/m ratios.random_select(range(1, m+1), n) — the functional decomposition is identical in both languages.v.sort() after selection costs O(k log k). In OCaml, List.sort compare does the same.OCaml Approach
OCaml's version: let lotto_select n m = let range = List.init m (fun i -> i + 1) in random_select range n. This reuses random_select from problem 23, passing the range [1; 2; ...; m] as the source list. OCaml's List.init generates the range eagerly. To sort the result for display: List.sort compare selected.
OCaml's lotto: let lotto_select n m = rand_select (range 1 m) n. This composes the range generator from problem 22 and the random selector from problem 23 — exactly the same composition as Rust's approach. The elegance of functional composition: new problems reduce to combinations of previous solutions.
Full Source
#![allow(clippy::all)]
// Placeholder — pending conversionDeep Comparison
OCaml vs Rust: Lotto Draw
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
simulate_lottery(draws: usize, k: usize, m: u32) -> Vec<Vec<u32>> that performs draws independent lotto draws and returns them all sorted.lotto_select to return the drawn numbers in ascending order — lottery results are always displayed sorted. Use .sort() on the result.lotto_multi(n: usize, m: usize, draws: usize) -> Vec<Vec<usize>> that performs multiple independent lottery draws, ensuring no two draws produce the same combination.