919-iterator-any-all — Iterator any and all
Tutorial
The Problem
Existential and universal quantification over sequences — "does any element satisfy X?" and "do all elements satisfy X?" — are fundamental logic operations. In formal logic, ∃ (exists) and ∀ (for all). In SQL, EXISTS and NOT EXISTS. In Haskell, any and all. In OCaml, List.exists and List.for_all. Rust's Iterator::any() and Iterator::all() short-circuit: any stops at the first true, all stops at the first false. This makes them efficient even on large sequences and safe on infinite iterators (as long as the condition is eventually met).
🎯 Learning Outcomes
.any(pred) for existential checking (∃ — short-circuits on first true).all(pred) for universal checking (∀ — short-circuits on first false).all() on an empty iterator returns true.any() on an empty iterator returns falseList.exists and List.for_allCode Example
#![allow(clippy::all)]
//! 280. Existential checks: any() and all()
//!
//! `any(pred)` is ∃, `all(pred)` is ∀ — both short-circuit.
#[cfg(test)]
mod tests {
#[test]
fn test_any_true() {
assert!([1i32, 2, 3].iter().any(|&x| x == 2));
}
#[test]
fn test_any_false() {
assert!(![1i32, 2, 3].iter().any(|&x| x == 9));
}
#[test]
fn test_all_true() {
assert!([2i32, 4, 6].iter().all(|&x| x % 2 == 0));
}
#[test]
fn test_all_false() {
assert!(![1i32, 2, 3].iter().all(|&x| x % 2 == 0));
}
#[test]
fn test_vacuous_truth() {
let empty: Vec<i32> = vec![];
assert!(empty.iter().all(|_| false)); // vacuously true
assert!(!empty.iter().any(|_| true)); // no elements
}
}Key Differences
any/all in Rust and exists/for_all in OCaml have exactly the same short-circuit behavior and vacuous truth/false rules.iter.any(pred); OCaml uses function syntax List.exists pred xs.(0..).any(|x| x > 100) terminates; (0..).all(|x| x < 100) would loop forever — same constraint applies to OCaml Seq.!any(pred) = all(!pred) by De Morgan's law — both languages implement this complementary relationship.OCaml Approach
List.exists: ('a -> bool) -> 'a list -> bool — equivalent to any. List.for_all: ('a -> bool) -> 'a list -> bool — equivalent to all. Both short-circuit. Vacuous behavior: List.for_all pred [] = true; List.exists pred [] = false. For sequences: Seq.exists and Seq.for_all (since 4.14). The semantics are identical to Rust's; the difference is method vs function call syntax.
Full Source
#![allow(clippy::all)]
//! 280. Existential checks: any() and all()
//!
//! `any(pred)` is ∃, `all(pred)` is ∀ — both short-circuit.
#[cfg(test)]
mod tests {
#[test]
fn test_any_true() {
assert!([1i32, 2, 3].iter().any(|&x| x == 2));
}
#[test]
fn test_any_false() {
assert!(![1i32, 2, 3].iter().any(|&x| x == 9));
}
#[test]
fn test_all_true() {
assert!([2i32, 4, 6].iter().all(|&x| x % 2 == 0));
}
#[test]
fn test_all_false() {
assert!(![1i32, 2, 3].iter().all(|&x| x % 2 == 0));
}
#[test]
fn test_vacuous_truth() {
let empty: Vec<i32> = vec![];
assert!(empty.iter().all(|_| false)); // vacuously true
assert!(!empty.iter().any(|_| true)); // no elements
}
}#[cfg(test)]
mod tests {
#[test]
fn test_any_true() {
assert!([1i32, 2, 3].iter().any(|&x| x == 2));
}
#[test]
fn test_any_false() {
assert!(![1i32, 2, 3].iter().any(|&x| x == 9));
}
#[test]
fn test_all_true() {
assert!([2i32, 4, 6].iter().all(|&x| x % 2 == 0));
}
#[test]
fn test_all_false() {
assert!(![1i32, 2, 3].iter().all(|&x| x % 2 == 0));
}
#[test]
fn test_vacuous_truth() {
let empty: Vec<i32> = vec![];
assert!(empty.iter().all(|_| false)); // vacuously true
assert!(!empty.iter().any(|_| true)); // no elements
}
}
Exercises
.any() and .all() to implement is_valid_sudoku_row(row: &[u8]) -> bool that checks for values 1-9 with no duplicates.has_balanced_parens(s: &str) -> bool using .scan() on chars and .all() on the running count.exactly_one<T>(data: &[T], pred: impl Fn(&T) -> bool) -> bool that returns true if exactly one element satisfies the predicate.