Convert hash to hash in Rust

HashMap new from from_iter insert map collect

In a recent project I had a HashMap and I needed to create another HashMap using the same keys, and calculating the value based on the values from the original hash. More precisely I had to calculate the percentage of each value from the total and convert it into a string to be displayed later.

In the following example we'll see two approaches for this and we'll see the second approach twice to make it clearer.

In the first case I've creates an empty mutable HashMap, iterated over the keys and inserted the new key-value pairs.

    let mut perc: HashMap<&str, String> = HashMap::new();
    for field in stats.keys() {
        perc.insert(field, percentage(stats[field], total));
    }

In the second example I took a more "functional" approach.

    let perc: HashMap<&&str, String> = HashMap::from_iter(
        stats
            .iter()
            .map(|(k, v)| (k, percentage(*v, total)))
            .collect::<Vec<(&&str, String)>>(),
    );

As it felt a bit too complex I also created a two-step version of this approach. First we create a vector of tuples that will be the future key-value pairs of the new HashMap and then we build the hash using the from_iter call.

    let pairs = stats
        .iter()
        .map(|(k, v)| (k, percentage(*v, total)))
        .collect::<Vec<(&&str, String)>>();
    let perc: HashMap<&&str, String> = HashMap::from_iter(pairs);

The full code

examples/convert-hash-to-hash/src/main.rs

use std::collections::HashMap;

fn main() {
    with_mutable();
    println!("---------------");
    functional();
    println!("---------------");
    functional_temp();
}

fn with_mutable() {
    let stats: HashMap<&str, usize> = HashMap::from([("red", 10), ("green", 39), ("blue", 23)]);

    let total = stats.values().sum::<usize>();

    let mut perc: HashMap<&str, String> = HashMap::new();
    for field in stats.keys() {
        perc.insert(field, percentage(stats[field], total));
    }

    dbg!(&stats);
    dbg!(total);
    dbg!(perc);
}

fn functional() {
    let stats: HashMap<&str, usize> = HashMap::from([("red", 10), ("green", 39), ("blue", 23)]);

    let total = stats.values().sum::<usize>();

    let perc: HashMap<&&str, String> = HashMap::from_iter(
        stats
            .iter()
            .map(|(k, v)| (k, percentage(*v, total)))
            .collect::<Vec<(&&str, String)>>(),
    );

    dbg!(&stats);
    dbg!(total);
    dbg!(perc);
}

fn functional_temp() {
    let stats: HashMap<&str, usize> = HashMap::from([("red", 10), ("green", 39), ("blue", 23)]);

    let total = stats.values().sum::<usize>();

    let pairs = stats
        .iter()
        .map(|(k, v)| (k, percentage(*v, total)))
        .collect::<Vec<(&&str, String)>>();
    let perc: HashMap<&&str, String> = HashMap::from_iter(pairs);

    dbg!(&stats);
    dbg!(total);
    dbg!(perc);
}

pub fn percentage(num: usize, total: usize) -> String {
    let total = (10000.0 * num as f32 / total as f32).floor();
    (total / 100.0).to_string()
}

Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo