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

后端 未结 2 1399
后悔当初
后悔当初 2020-12-06 04:01

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

2条回答
  •  南笙
    南笙 (楼主)
    2020-12-06 04:46

    Use Iterator::collect:

    use std::collections::HashMap;
    
    fn main() {
        let tuples = vec![("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<(K, V)> 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.

    See also:

    • Collect iterators of length 2 into HashMap

    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<(K, V)> 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?

提交回复
热议问题