HiveBrain v1.2.0
Get Started
← Back to all entries
snippetrustCritical

How do I create a map from a list in a functional way?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
howfromcreatefunctionallistwaymap

Problem

In Scala, there is a method named toMap that works on any list of tuples and converts it to a map where the key is the first item on the tuple and the value is the second one:

val listOfTuples = List(("one", 1), ("two", 2))
val map = listOfTuples.toMap


What is the closest thing to toMap in Rust?

Solution

Use Iterator::collect:

use std::collections::HashMap;

fn main() {
    let tuples = [("one", 1), ("two", 2), ("three", 3)];
    let m: HashMap = tuples.into_iter().collect();
    println!("{:?}", m);
}


collect leverages the FromIterator trait. Any iterator can be collected into a type that implements FromIterator. In this case, HashMap implements it as:

impl FromIterator for HashMap
where
    K: Eq + Hash,
    S: HashState + Default,


Said another way, any iterator of tuples where the first value can be hashed and compared for total equality can be converted to a HashMap. The S parameter isn't exciting to talk about, it just defines what the hashing method is.

With this knowledge, you can also call FromIterator directly:

use std::collections::HashMap;

fn main() {
    let m: HashMap = HashMap::from_iter([("one", 1), ("two", 2), ("three", 3)]);
    println!("{:?}", m);
}


See also:

  • Collect iterators of length 2 into HashMap



  • How do I create a HashMap literal?



what change should I make so that I get all the values with same key stored in a Vec?

There's no one-line / functional method for this in the standard library. Instead, use the entry API:

use std::collections::HashMap;

fn main() {
    let tuples = vec![("one", 1), ("two", 2), ("one", 3)];
    let mut m = HashMap::new();
    for (k, v) in tuples {
        m.entry(k).or_insert_with(Vec::new).push(v)
    }
    println!("{:?}", m);
}


If you found yourself doing this frequently, you could create your own type and implement FromIterator for it:

use std::{cmp::Eq, collections::HashMap, hash::Hash, iter::FromIterator};

struct MyCoolType(HashMap>);

impl FromIterator for MyCoolType {
    fn from_iter(tuples: I) -> Self
    where
        I: IntoIterator,
    {
        let mut m = HashMap::new();
        for (k, v) in tuples {
            m.entry(k).or_insert_with(Vec::new).push(v)
        }
        Self(m)
    }
}

fn main() {
    let tuples = vec![("one", 1), ("two", 2), ("one", 3)];
    let MyCoolType(m) = tuples.into_iter().collect();
    println!("{:?}", m);
}


See also:

  • How to lookup from and insert into a HashMap efficiently?

Code Snippets

use std::collections::HashMap;

fn main() {
    let tuples = [("one", 1), ("two", 2), ("three", 3)];
    let m: HashMap<_, _> = tuples.into_iter().collect();
    println!("{:?}", m);
}
impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
where
    K: Eq + Hash,
    S: HashState + Default,
use std::collections::HashMap;

fn main() {
    let m: HashMap<_, _> = HashMap::from_iter([("one", 1), ("two", 2), ("three", 3)]);
    println!("{:?}", m);
}
use std::collections::HashMap;

fn main() {
    let tuples = vec![("one", 1), ("two", 2), ("one", 3)];
    let mut m = HashMap::new();
    for (k, v) in tuples {
        m.entry(k).or_insert_with(Vec::new).push(v)
    }
    println!("{:?}", m);
}
use std::{cmp::Eq, collections::HashMap, hash::Hash, iter::FromIterator};

struct MyCoolType<K: Eq + Hash, V>(HashMap<K, Vec<V>>);

impl<K: Eq + Hash, V> FromIterator<(K, V)> for MyCoolType<K, V> {
    fn from_iter<I>(tuples: I) -> Self
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let mut m = HashMap::new();
        for (k, v) in tuples {
            m.entry(k).or_insert_with(Vec::new).push(v)
        }
        Self(m)
    }
}

fn main() {
    let tuples = vec![("one", 1), ("two", 2), ("one", 3)];
    let MyCoolType(m) = tuples.into_iter().collect();
    println!("{:?}", m);
}

Context

Stack Overflow Q#30441698, score: 143

Revisions (0)

No revisions yet.