Skip to content

← Collections, Text and First Iterators step 7 of 21

Easy Primitives

Look up and update HashMap values

Fix two functions that build a HashMap<String, i64> from key-value pairs. One reports values for requested keys; the other increments existing values.

pub fn lookup_report(pairs: Vec<(String, i64)>, queries: Vec<String>) -> Vec<i64>
pub fn bump_present(pairs: Vec<(String, i64)>, keys: Vec<String>) -> Vec<(String, i64)>

Required behavior

Each function builds its own map. Insert pairs in input order so the last value for a duplicate key replaces earlier values. Compare keys exactly: "A", "a" and " a" are different keys. Empty strings are valid keys.

  • lookup_report: return one value per query, in query order. Return -1 for a missing key. Repeated queries produce repeated results. A stored value of -1 also returns -1; this output format does not distinguish it from an absent key.
  • bump_present: process keys in order, adding 1 whenever the key exists. Ignore missing keys without inserting them. Repeated keys cause repeated increments. Return every map entry, including untouched entries, sorted by key using Rust's String ordering.

Inputs are chosen so every increment fits in i64. An empty pairs vector means every query is missing and the update result is empty. Empty queries produces no lookup results; empty keys leaves the map's values unchanged.

For example, with pairs = [("a", 1), ("b", -1), ("a", 5)]:

queries = ["b", "missing", "a", "a"]
lookup_report returns [-1, -1, 5, 5]

keys = ["a", "missing", "a"]
bump_present returns [("a", 7), ("b", -1)]

The lookup result uses the original pairs, independently of the increments.

Borrow a key to find an entry

get returns Option<&i64> here. copied() copies a present integer out of its reference, and unwrap_or(-1) supplies this exercise's missing value. Indexing with map[q] instead panics when q is absent.

Use get_mut to change an existing value. It returns None for a missing key, so an if let Some(value) block can skip it.

This complete example shows both operations:

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert(String::from("score"), 4_i64);

    assert_eq!(map.get("missing").copied().unwrap_or(-1), -1);
    if let Some(value) = map.get_mut("score") {
        *value += 1;
    }
    assert_eq!(map.get("score"), Some(&5));
}

A String key can be looked up through &str or &String. The borrowed form must have matching equality and hashing behavior. remove also accepts a borrowed key, but it deletes the entry rather than merely reading it.

In contrast, entry takes an owned String because its result can be used to insert a missing key. The starter passes &String, causing a type error. get_mut fits the requested update without cloning a key or inserting one.

Return entries in the requested order

HashMap iteration is arbitrary. Keep the final vector sort in bump_present to meet this task's output contract. It does not depend on the order in which the map happens to yield entries.

See the HashMap API for the method signatures. Passing this exercise requires compilation, the test cases and Clippy with warnings denied.