Collect() with tuples


#1

Hi Rusty humans,
I’m new to Rust, and I’m trying to figure out how to collect() a Vec of (u32, &str) tuples. I have this code below:

use std::collections::HashMap;
fn main() {
    let mut m: HashMap<u32, &str> = HashMap::new();
    m.insert(1, "hello");
    m.insert(2, "world");
    let v: Vec<u32> = vec![1,2,3];
    let b: Vec<(u32, &str)> = v 
        .iter()
        .flat_map( |&k| m.get(&k).map(|v| (k,v)).into_iter() )
        .collect();  // error here
    for (x,y) in b {
        println!("{},{}", x,y);
    }
}

If I change let b: Vec<(u32, &str)> to let b: Vec<_>, this compiles and runs as expected. My slim understanding is that the tuple would need to implement FromIterator, though I’m probably way off base. Could someone more enlightened than me explain how I could specify let b: Vec<(u32, &str)> instead?

Link to code at play-rust: http://preview.tinyurl.com/obrbddj

leo


#2

Your HashMap is mapping u32s to &strs and HashMap::get returns an optional reference to the value stored in the hash map (not the value itself). Therefore, HashMap::get is returning Option<&&str> (a reference to the &str you’re putting into the HashMap. To fix this, you need to dereference the &&str you’re getting out of the HashMap.

For example,

use std::collections::HashMap;
fn main() {
    let mut m: HashMap<u32, &str> = HashMap::new();
    m.insert(1, "hello");
    m.insert(2, "world");
    let v: Vec<u32> = vec![1,2,3];
    let b: Vec<(u32, &str)> = v 
        .iter()
        .flat_map( |&k| m.get(&k).map(|&v| (k,v)).into_iter() )
        .collect();  // error here
    for (x,y) in b {
        println!("{},{}", x,y);
    }
}

#3

#facepalm

Thanks, stebalien!


#4

Also note that filter_map might be a bit more convenient here than flat_map:

use std::collections::HashMap;
    
fn main() {
    let mut m: HashMap<u32, &str> = HashMap::new();
    m.insert(1, "hello");
    m.insert(2, "world");
    let v: Vec<u32> = vec![1,2,3];
    let b: Vec<(u32, &str)> = v 
        .iter()
        .filter_map(|&k| m.get(&k).map(|&v| (k, v)))
        .collect();
    for (x,y) in b {
        println!("{},{}", x,y);
    }
}