Lesson 8 of 12

Collections & Iterators

Learn the standard collections and how to them with . A chain of map, filter and sum compiles to code as fast as a hand-written .

Rust
use std::collections::{HashMap, HashSet, BTreeMap, VecDeque};

fn main() {
    // Vec — growable array, the workhorse
    let mut nums = vec![3, 1, 4, 1, 5];
    nums.push(9);
    nums.sort();
    nums.dedup();
    println!("{:?}", nums);                 // [1, 3, 4, 5, 9]
    println!("{:?}", nums.first());         // Some(1)  — never panics
    println!("{:?}", nums.get(99));         // None     — unlike nums[99]

    // HashMap
    let mut scores: HashMap<String, i32> = HashMap::new();
    scores.insert("ada".to_string(), 10);

    // entry() is the idiomatic get-or-insert
    *scores.entry("ada".into()).or_insert(0) += 5;
    *scores.entry("bob".into()).or_insert(0) += 1;
    println!("{:?}", scores.get("ada"));    // Some(15)

    for (name, score) in &scores {
        println!("{name}: {score}");
    }

    // HashSet for membership, BTreeMap for sorted keys, VecDeque for a queue
    let seen: HashSet<i32> = nums.iter().copied().collect();
    let sorted: BTreeMap<&str, i32> = BTreeMap::from([("b", 2), ("a", 1)]);
    let mut queue: VecDeque<i32> = VecDeque::from([1, 2, 3]);
    queue.push_back(4);
    println!("{:?} {:?} {:?}", seen.contains(&4), sorted.keys().collect::<Vec<_>>(), queue.pop_front());
}
Rust
#[derive(Debug, Clone)]
struct Order { customer: String, region: String, total: f64 }

fn main() {
    let orders = vec![
        Order { customer: "Ada".into(),  region: "EU".into(), total: 120.5 },
        Order { customer: "Bob".into(),  region: "US".into(), total: 45.0 },
        Order { customer: "Cleo".into(), region: "EU".into(), total: 310.75 },
    ];

    // Three ways to iterate — the difference is ownership:
    //   .iter()      -> &T      borrow each item
    //   .iter_mut()  -> &mut T  borrow mutably
    //   .into_iter() -> T       consume the collection
    let total: f64 = orders.iter().map(|o| o.total).sum();
    println!("{total:.2}");                          // 476.25

    let eu_names: Vec<&str> = orders
        .iter()
        .filter(|o| o.region == "EU")
        .map(|o| o.customer.as_str())
        .collect();
    println!("{eu_names:?}");                        // ["Ada", "Cleo"]

    // Nothing runs until a consuming adapter: collect, sum, count, for_each, fold
    let biggest = orders.iter().max_by(|a, b| a.total.total_cmp(&b.total));
    println!("{:?}", biggest.map(|o| &o.customer));

    let summary = orders.iter().fold(String::new(), |mut acc, o| {
        acc.push_str(&format!("{} ", o.customer));
        acc
    });
    println!("{}", summary.trim());
}
Rust
use std::collections::HashMap;

fn main() {
    let words = ["apple", "banana", "avocado", "blueberry", "cherry"];

    // Grouping
    let mut by_letter: HashMap<char, Vec<&str>> = HashMap::new();
    for w in words {
        by_letter.entry(w.chars().next().unwrap()).or_default().push(w);
    }
    println!("{:?}", by_letter.get(&'a'));      // Some(["apple", "avocado"])

    // The adapters worth memorising
    let nums: Vec<i32> = (1..=10).collect();
    println!("{:?}", nums.iter().enumerate().take(2).collect::<Vec<_>>());
    println!("{:?}", nums.iter().zip("abc".chars()).collect::<Vec<_>>());
    println!("{:?}", nums.iter().skip(8).collect::<Vec<_>>());
    println!("{:?}", nums.chunks(3).next());
    println!("{:?}", nums.windows(2).next());
    println!("{}",   nums.iter().any(|&n| n > 9));
    println!("{}",   nums.iter().all(|&n| n > 0));
    println!("{:?}", nums.iter().position(|&n| n == 7));
    println!("{:?}", nums.iter().rev().take(3).collect::<Vec<_>>());

    // filter_map: filter and transform in one pass
    let inputs = ["1", "two", "3"];
    let parsed: Vec<i32> = inputs.iter().filter_map(|s| s.parse().ok()).collect();
    println!("{parsed:?}");                     // [1, 3]

    // collect into a Result: fails fast if ANY item fails
    let all: Result<Vec<i32>, _> = inputs.iter().map(|s| s.parse::<i32>()).collect();
    println!("{}", all.is_err());               // true
}
Finished reading?Mark it done to track your progress.

Tip: use the ← and → keys to move between lessons.