firechant
firechant

Reputation: 976

Is there any way to insert multiple entries into a HashMap at once in Rust?

Is there any way to insert multiple entries into a HashMap at once in Rust? Or to initialize it with multiple entries? Anything other than manually calling insert on every single element you're inserting?

Edit for an example using English letter frequencies:

I basically want:

let frequencies = { 
  'a': 0.08167, 
  'b': 0.01492, 
  ... 
  'z': 0.00074 
}

I know I can achieve the same result by doing a for loop like the following, but I want to know if there is a way to do this without creating additional arrays and then looping over them, or a more elegant solution in general.

let mut frequencies = HashMap::new();
let letters = ['a','b','c', ...... 'z'];
let freqs = [0.08167, 0.01492, 0.02782, ......., 0.00074];
for i in 0..26 {
    frequencies.insert(letters[i], freqs[i]);
}

For a literal, I could use the answer here, which will probably work fine for this example, but I'm curious whether there's a way to do this without it being a literal, in case this comes up in the future.

Upvotes: 11

Views: 10719

Answers (2)

Claudio Fsr
Claudio Fsr

Reputation: 434

use std::collections::HashMap;

fn main() {
    let pairs = [
        ("a", 1),
        ("b", 2),
        ("c", 3),
        ("z", 50),
    ];

    println!("1. Insert multiple entries into a HashMap at once");
    let mut map = HashMap::new();
    map.extend(pairs);
    println!("map: {map:#?}\n");
    
    println!("2. Initialize with multiple entries");
    let map = HashMap::from([
        ("a", 1),
        ("b", 2),
        ("c", 3),
        ("z", 50),
    ]);
    println!("map: {map:#?}\n");

    println!("3. Initialize with multiple entries");
    let map = HashMap::from(pairs);
    println!("map: {map:#?}\n");
    
    println!("4. Initialize with multiple entries");
    let map: HashMap<_, _> = pairs.into();
    println!("map: {map:#?}");
}

See the Rust Playground.

Upvotes: 1

ArtemGr
ArtemGr

Reputation: 12547

Is there any way to insert multiple entries into a HashMap at once in Rust?

Yes, you can extend a HashMap with values from an Iterator, like this:

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.extend((1..3).map(|n| (format!("{}*2=", n), n * 2)));
    map.extend((7..9).map(|n| (format!("{}*2=", n), n * 2)));
    println!("{:?}", map); // Prints {"1*2=": 2, "8*2=": 16, "7*2=": 14, "2*2=": 4}.
}

It is even a bit faster than calling the insert manually, because extend uses the size hint provided by the Iterator in order to reserve some space beforehand.

Check out the source code of the method here, in map.rs.

Or to initialize it with multiple entries?

This is possible as well, thanks to HashMap implementing the FromIterator trait. When a collection implements FromIterator, you can use the Iterator::collect shorthand to construct it. Consider the following examples, all of them generating the same map:

use std::collections::HashMap;

fn main() {
    let mut map: HashMap<_, _> = (1..3).map(|n| (format!("{}*2=", n), n * 2)).collect();
    map.extend((7..9).map(|n| (format!("{}*2=", n), n * 2)));
    println!("{:?}", map); // Prints {"1*2=": 2, "8*2=": 16, "7*2=": 14, "2*2=": 4}.
}

use std::collections::HashMap;

fn main() {
    let map: HashMap<_, _> = (1..3)
        .chain(7..9)
        .map(|n| (format!("{}*2=", n), n * 2))
        .collect();
    println!("{:?}", map); // Prints {"1*2=": 2, "8*2=": 16, "7*2=": 14, "2*2=": 4}.
}

use std::collections::HashMap;
use std::iter::FromIterator;

fn main() {
    let iter = (1..3).chain(7..9).map(|n| (format!("{}*2=", n), n * 2));
    let map = HashMap::<String, u32>::from_iter(iter);
    println!("{:?}", map); // Prints {"1*2=": 2, "8*2=": 16, "7*2=": 14, "2*2=": 4}.
}

Upvotes: 20

Related Questions