โข Option
โข Result
โข 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
โข Option
โข Result
โข 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
// Duplicate Elements โ 99 Problems #14
// Duplicate every element: [a, b, c] โ [a, a, b, b, c, c]
fn duplicate<T: Clone>(lst: &[T]) -> Vec<T> {
lst.iter().flat_map(|x| [x.clone(), x.clone()]).collect()
}
/// Tail-recursive style with explicit accumulator.
fn duplicate_tr<T: Clone>(lst: &[T]) -> Vec<T> {
let mut acc = Vec::with_capacity(lst.len() * 2);
for x in lst {
acc.push(x.clone());
acc.push(x.clone());
}
acc
}
/// Using concat_map (flat_map) โ closest to OCaml style.
fn duplicate_map<T: Clone>(lst: &[T]) -> Vec<T> {
lst.iter().flat_map(|x| vec![x.clone(), x.clone()]).collect()
}
fn main() {
let nums = vec![1, 2, 3, 4];
println!("Input: {:?}", nums);
println!("Doubled: {:?}", duplicate(&nums));
let chars = vec!['a', 'b', 'c'];
println!("Chars: {:?}", chars);
println!("Doubled: {:?}", duplicate(&chars));
println!("TR: {:?}", duplicate_tr(&chars));
println!("Map: {:?}", duplicate_map(&chars));
let empty: Vec<i32> = vec![];
println!("Empty: {:?}", duplicate(&empty));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_duplicate_empty() {
let empty: Vec<i32> = vec![];
assert_eq!(duplicate(&empty), vec![]);
}
#[test]
fn test_duplicate_single() {
assert_eq!(duplicate(&[1]), vec![1, 1]);
}
#[test]
fn test_duplicate_multiple() {
assert_eq!(duplicate(&[1, 2, 3]), vec![1, 1, 2, 2, 3, 3]);
}
#[test]
fn test_all_versions_match() {
let input = vec!['a', 'b', 'c'];
let d = duplicate(&input);
assert_eq!(d, duplicate_tr(&input));
assert_eq!(d, duplicate_map(&input));
}
}
(* Duplicate Elements โ 99 Problems #14 *)
(* Duplicate every element: [a;b;c] โ [a;a;b;b;c;c] *)
(* โโ Recursive โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ *)
let rec duplicate = function
| [] -> []
| h :: t -> h :: h :: duplicate t
(* โโ Tail-recursive with accumulator โโโโโโโโโโโโโโโโโโโโโโโ *)
let duplicate_tr lst =
let rec aux acc = function
| [] -> List.rev acc
| h :: t -> aux (h :: h :: acc) t
in aux [] lst
(* โโ Using concat_map โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ *)
let duplicate_map lst =
List.concat_map (fun x -> [x; x]) lst
(* โโ Tests โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ *)
let () =
assert (duplicate [] = []);
assert (duplicate [1] = [1; 1]);
assert (duplicate [1; 2; 3] = [1; 1; 2; 2; 3; 3]);
assert (duplicate_tr ['a'; 'b'; 'c'] = ['a'; 'a'; 'b'; 'b'; 'c'; 'c']);
assert (duplicate_map [1; 2] = [1; 1; 2; 2]);
print_endline "โ Duplicate elements tests passed"
let rec duplicate = function
| [] -> []
| h :: t -> h :: h :: duplicate tlet duplicate_tr lst =
let rec aux acc = function
| [] -> List.rev acc
| h :: t -> aux (h :: h :: acc) t
in aux [] lstpub fn duplicate<T: Clone>(list: &[T]) -> Vec<T> {
list.iter().flat_map(|x| vec![x.clone(), x.clone()]).collect()
}
The imperative version with `push` is more efficient (avoids intermediate vec allocation):
for item in list {
result.push(item.clone());
result.push(item.clone());
}| Aspect | OCaml | Rust | ||
|---|---|---|---|---|
| Construction | `h :: h :: tail` (O(1) prepend) | `push` (O(1) amortized append) | ||
| Copying | Automatic (values shared) | Explicit `clone()` | ||
| Direction | Builds front-to-back (cons) | Builds back via push | ||
| Memory | New list nodes (GC) | Pre-allocatable Vec | ||
| One-to-many | `concat_map (fun x -> [x;x])` | `flat_map(\ | x\ | vec![x,x])` |