๐Ÿฆ€ Functional Rust

490: Fixed-Size String Arrays

Difficulty: 1 Level: Beginner Store and work with collections of strings โ€” both fixed-size arrays and growable vectors.

The Problem This Solves

When you have a known set of strings โ€” days of the week, command names, error messages โ€” you don't need a heap-allocated dynamic collection. A fixed-size array `[&str; 7]` lives on the stack, costs nothing to allocate, and conveys your intent: this list doesn't grow. But often you need to sort, filter, or search string collections. Whether you use `[&str; N]`, `Vec<&str>`, or `Vec<String>` depends on ownership: do you own the strings or just borrow them? This example shows the idiomatic patterns: when to use each type, how to sort case-insensitively, how to filter, and how to join a collection back into a single string.

The Intuition

Three string collection types: The key operation is slicing: both arrays and Vecs deref to `&[T]`, so all slice methods work on both.

How It Works in Rust

// Fixed array โ€” stack allocated, no heap
let days: [&str; 7] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

// Slice operations work on both arrays and Vecs
println!("{}", days.contains(&"Wed")); // true

// Sort a Vec (arrays can't be sorted in-place while borrowed)
let mut words = vec!["banana", "apple", "cherry"];
words.sort(); // lexicographic

// Case-insensitive sort
words.sort_by_key(|s| s.to_lowercase());

// Filter: retain keeps elements matching a predicate
let mut items: Vec<&str> = vec!["rust", "ruby", "go", "python"];
items.retain(|s| s.starts_with('r'));
// items == ["rust", "ruby"]

// Join: collect a slice into a single string
let joined = words.join(", "); // "apple, banana, cherry"

// Search
let pos = words.iter().position(|&s| s == "banana");

What This Unlocks

Key Differences

ConceptOCamlRust
Fixed string array`let a = ["a"; "b"]``let a: [&str; 2] = ["a", "b"]`
Sort`Array.sort compare a``vec.sort()` (in-place)
Filter`Array.to_list a \> List.filter f``vec.retain(\s\pred(s))`
Join`String.concat sep list``slice.join(sep)`
Contains`Array.mem x a``slice.contains(&x)`
// 490. Fixed-size string arrays
fn main() {
    // &str array โ€” compile-time known size
    let fruits: [&str; 5] = ["banana","apple","cherry","date","elderberry"];
    println!("count: {}", fruits.len());
    println!("first: {}", fruits[0]);
    println!("contains cherry: {}", fruits.contains(&"cherry"));

    // Sort a Vec<String>
    let mut words: Vec<String> = fruits.iter().map(|&s| s.to_string()).collect();
    words.sort();
    println!("sorted: {:?}", words);

    // Case-insensitive sort
    let mut mixed = vec!["Banana","apple","Cherry","DATE"];
    mixed.sort_by_key(|s| s.to_lowercase());
    println!("case-insensitive: {:?}", mixed);

    // Filter
    let long: Vec<&str> = fruits.iter().copied().filter(|s| s.len() > 5).collect();
    println!("len>5: {:?}", long);

    // Map + collect
    let upper: Vec<String> = fruits.iter().map(|s| s.to_uppercase()).collect();
    println!("upper[0]: {}", upper[0]);

    // Join
    println!("joined: {}", fruits.join(", "));

    // Total chars
    let total: usize = fruits.iter().map(|s| s.len()).sum();
    println!("total chars: {}", total);

    // Binary search (requires sorted)
    words.sort();
    match words.binary_search(&"cherry".to_string()) {
        Ok(i)  => println!("cherry at index {}", i),
        Err(i) => println!("cherry not found, would insert at {}", i),
    }
}

#[cfg(test)]
mod tests {
    #[test] fn test_sort()    { let mut v=vec!["c","a","b"]; v.sort(); assert_eq!(v,["a","b","c"]); }
    #[test] fn test_filter()  { let v=vec!["hi","hello","hey"]; let long:Vec<_>=v.iter().filter(|s|s.len()>2).collect(); assert_eq!(long.len(),1); }
    #[test] fn test_join()    { assert_eq!(["a","b","c"].join("-"),"a-b-c"); }
    #[test] fn test_bsearch() { let v=vec!["apple".to_string(),"banana".to_string()]; assert_eq!(v.binary_search(&"banana".to_string()),Ok(1)); }
}
(* 490. String arrays โ€“ OCaml *)
let () =
  let words = [|"banana";"apple";"cherry";"date";"elderberry"|] in
  Array.sort String.compare words;
  Printf.printf "sorted: %s\n" (String.concat " " (Array.to_list words));
  let long = Array.to_list words |> List.filter (fun s -> String.length s > 5) in
  Printf.printf "long: %s\n" (String.concat " " long);
  Printf.printf "has cherry: %b\n" (Array.exists ((=) "cherry") words);
  Printf.printf "total chars: %d\n"
    (Array.fold_left (fun a s -> a + String.length s) 0 words)