2
\$\begingroup\$

I have the following code which finds all the unique values from a hashmap of String to Vec. I cobbled it together (eventually as I was getting various borrow errors along the way), but it looks a mess to me and I'm looking for a more idiomatic way of doing it in rust.

fn main() {
 let mut my_map: HashMap<String, Vec<String>> = HashMap::new();
 my_map.insert("option1".to_string(), vec![String::from("sarah"), String::from("john")]);
 my_map.insert("option2".to_string(), vec![String::from("john"), String::from("mark")]);
 let x: Vec<String> = my_map.values().flat_map(|x| x).cloned().collect();
 // or use flatten() instead of flat_map(|x| x)
 let y: HashSet<&String> = HashSet::from_iter(x.iter());
 let mut z = y.iter().collect::<Vec<_>>();
 z.sort();
 println!("{:?}", z);
}

My idea was to flatmap the values from the map down into a simple vector, and then find the unique values (putting everything into a hashset), then converting back to a vector of strings.

The output is the sorted list of all unique names in the Vectors:

["john", "mark", "sarah"]

What would be a better implementation of this in rust?

asked Dec 29, 2021 at 18:17
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

You can collect into a different collection type, such as HashSet or BTreeSet. Both of these will eliminate duplicates, but entries in a HashSet will be in a random order (because the hash is randomized) while entries in a BTreeSet will be ordered (based on the Ord implementation for the element type).

use std::collections::{BTreeSet, HashMap};
fn main() {
 let mut my_map: HashMap<String, Vec<String>> = HashMap::new();
 my_map.insert("option1".to_string(), vec![String::from("sarah"), String::from("john")]);
 my_map.insert("option2".to_string(), vec![String::from("john"), String::from("mark")]);
 let b: BTreeSet<_> = my_map.values().flatten().collect();
 println!("{:?}", b);
}

Note that instead of annotating the variable type, you can use the "turbofish" to specify the collection type to collect into:

let b = my_map.values().flatten().collect::<BTreeSet<_>>();

itertools is a crate that provides lots of extension methods for iterators. Relevant here are methods such as unique and sorted_unstable.

use std::collections::HashMap;
use itertools::Itertools; // 0.10.3
fn main() {
 let mut my_map: HashMap<String, Vec<String>> = HashMap::new();
 my_map.insert("option1".to_string(), vec![String::from("sarah"), String::from("john")]);
 my_map.insert("option2".to_string(), vec![String::from("john"), String::from("mark")]);
 let x: Vec<_> = my_map.values().flatten().unique().sorted_unstable().collect();
 println!("{:?}", x);
}
answered Dec 29, 2021 at 23:14
\$\endgroup\$
1
  • \$\begingroup\$ Good answer. One clarification: turbofish isn't an operator. It's a different kind of type annotation. \$\endgroup\$ Commented Jan 1, 2022 at 17:10

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.