//! 271. Transform-and-find with find_map()
//!
//! `find_map(f)` finds the first `Some(...)` result โ single pass, lazy.
fn main() {
let strings = ["hello", "42", "world", "17", "foo"];
let first_int = strings.iter().find_map(|s| s.parse::<i32>().ok());
println!("First int: {:?}", first_int);
let first_long_len = strings.iter()
.find_map(|s| if s.len() > 4 { Some(s.len()) } else { None });
println!("First long word length: {:?}", first_long_len);
let env_vars = ["PATH=/usr/bin", "HOME=/root", "BAD", "USER=alice"];
let first_kv = env_vars.iter().find_map(|s| {
let mut parts = s.splitn(2, '=');
let key = parts.next()?;
let val = parts.next()?;
Some((key, val))
});
println!("First key=value: {:?}", first_kv);
let files = ["main.txt", "lib.rs", "README.md", "util.rs"];
let first_rs_stem = files.iter().find_map(|f| f.strip_suffix(".rs"));
println!("First .rs stem: {:?}", first_rs_stem);
// Equivalence with filter_map + next
let equiv = strings.iter().filter_map(|s| s.parse::<i32>().ok()).next();
assert_eq!(first_int, equiv);
println!("find_map == filter_map+next: true");
}
#[cfg(test)]
mod tests {
#[test]
fn test_find_map_parse() {
let strings = ["foo", "bar", "42", "baz"];
let result = strings.iter().find_map(|s| s.parse::<i32>().ok());
assert_eq!(result, Some(42));
}
#[test]
fn test_find_map_none() {
let strings = ["foo", "bar"];
let result = strings.iter().find_map(|s| s.parse::<i32>().ok());
assert_eq!(result, None);
}
#[test]
fn test_find_map_first_match() {
let nums = [1i32, 2, 3, 4, 5];
let result = nums.iter().find_map(|&x| if x > 3 { Some(x * 10) } else { None });
assert_eq!(result, Some(40));
}
}
(* 271. Transform-and-find with find_map() - OCaml *)
let find_map f lst =
let rec aux = function
| [] -> None
| x :: xs -> (match f x with Some _ as r -> r | None -> aux xs)
in aux lst
let () =
let strings = ["hello"; "42"; "world"; "17"; "foo"] in
let first_int = find_map int_of_string_opt strings in
Printf.printf "First int: %s\n"
(match first_int with Some n -> string_of_int n | None -> "None");
let first_long_len = find_map (fun w ->
let l = String.length w in if l > 4 then Some l else None
) strings in
Printf.printf "First long word length: %s\n"
(match first_long_len with Some n -> string_of_int n | None -> "None");
let env_vars = ["PATH=/usr/bin"; "HOME=/root"; "BAD"; "USER=alice"] in
let first_kv = find_map (fun s ->
match String.split_on_char '=' s with
| [k; v] -> Some (k, v)
| _ -> None
) env_vars in
match first_kv with
| Some (k, v) -> Printf.printf "First valid var: %s=%s\n" k v
| None -> print_endline "None"