Filtering keys in hashmap in rust - rust

I am not able to figure out why I am not getting keys filtered properly any hints
use std::collections::HashMap;
fn main() {
let mut h: HashMap<&str, &str> = HashMap::new();
h.insert("Hello", "World");
h.insert("Aloha", "Wilkom");
let dummy = h.keys().filter(|x| x.contains("Aloha"));
println!("{:?}", dummy);
}
Output shows both the keys. I would expect only the key that matched
Filter { iter: ["Hello", "Aloha"] }

This is an artifact of the Debug impl for filter's return value. If you collect the keys into a Vec it works as expected:
use std::collections::HashMap;
fn main() {
let mut h:HashMap<&str,&str> = HashMap::new();
h.insert("Hello","World");
h.insert("Aloha","Wilkom");
let dummy: Vec<_> = h.keys().filter(|x| x.contains("Aloha")).collect();
println!("{:?}",dummy);
}
(playground)
If you directly print out Filter, you get:
Filter { iter: ["Aloha", "Hello"] }
which technically is correct: dummy is a filter based on the iterator ["Aloha", "Hello"]

Related

How to insert to a HashSet<i32> which is the value of HashMap<i32, HashSet<i32>> in Rust?

I am implementing a HashMap<i32, HashSet<i32>>, and I want to call insert to the value HashSet<i32> given key of the HashMap. Here is my attempt:
use std::collections::HashMap;
use std::collections::HashSet;
fn main() {
let map: HashMap<i32, HashSet<i32>> = HashMap::new();
map.insert(1, HashSet::new());
map.entry(1).insert(1);
println!("{:?}", map);
}
and the compiler says:
error[E0599]: no method named `insert` found for enum `std::collections::hash_map::Entry` in the current scope
--> src/main.rs:7:18
|
7 | map.entry(1).insert(1);
| ^^^^^^ help: there is an associated function with a similar name: `insert_entry`
Why can not method entry used to change HashMap's value? Can anyone fix this for me?
map.entry(1) returns an Entry not the value in the map (to cover the case where the key is not found). In your case, you can merge the two map lines together
let map: HashMap<i32, HashSet<i32>> = HashMap::new();
// HashSet implements Default so `or_default()` will
// insert an empty set and return a mutable reference to it.
map.entry(1).or_default().insert(1);
println!("{:?}", map);
use std::collections::HashMap;
use std::collections::HashSet;
fn main() {
let mut map: HashMap<i32, HashSet<i32>> = HashMap::new();
map.insert(1, HashSet::new());
let iter = map.entry(1).or_insert(HashSet::new());
iter.insert(1);
println!("{:?}", map);
}

Translating JSON object into HashMap with serde_json

I'm trying to parse a JSON object into a HashMap in Rust using serde_json. With the following code, I get the error:
error[E0507]: cannot move out of index of `Value`
How do I get that Value into my HashMap?
use serde_json::{Result, Value};
use std::collections::HashMap;
fn main() {
let variables_json = r#"{
"awayTeamAbbrev": "DAL",
"homeTeamAbbrev": "TB",
"gameInstanceUid": "cbs-nfl-pickem-challenge",
"sportType": "NFL",
"weekNumber": 1
}"#;
let keys = vec!["sportType","weekNumber"];
dbg!(json_to_hashmap(&variables_json, keys));
}
fn json_to_hashmap(json: &str, keys: Vec<&str>) -> Result<HashMap<String, Value>> {
let lookup: Value = serde_json::from_str(json).unwrap();
let mut map = HashMap::new();
for key in keys {
let varname = key.to_owned();
let value = lookup[&varname];
map.insert(varname, value);
}
Ok(map)
}
You can get a HashMap<String, Value> directly from serde_json::from_str, then use remove_entry to take the values out without cloning:
fn json_to_hashmap(json: &str, keys: Vec<&str>) -> Result<HashMap<String, Value>> {
let mut lookup: HashMap<String, Value> = serde_json::from_str(json).unwrap();
let mut map = HashMap::new();
for key in keys {
let (k, v) = lookup.remove_entry (key).unwrap();
map.insert(k, v);
}
Ok(map)
}
Playground

Rust same mutable reference in multiple vectors

I am trying to store an object into 2 different reference vectors, and if I modify the object from first vector ref, it should be visible from the second vector.
I still haven't understood well borrowing so that's what I'm trying to acheive :
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
use std::vec::Vec;
struct A {
x: u32,
}
impl Display for A {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}", self.x)
}
}
fn main() {
let mut a = A{x: 1};
let mut v1: Vec<&mut A> = Vec::new();
let mut v2: Vec<&mut A> = Vec::new();
v1.push(&mut a);
v2.push(&mut a);
let f: &mut A = v1[0];
f.x = 3;
for v in &v1 {
println!("Value: {}", v);
}
for v in &v2 {
println!("Value: {}", v);
}
}
Of course this doesn't compile. What should I do to be able to store same object in different collection like objects ? (I don't see any concurency issue or borrowing here).

How do I find the key for a value in a HashMap?

I have a std::collections::HashMap that contains some entries. I want to find the key that corresponds to a particular value that is already in the hash map.
Iterate over the entries of the HashMap, find the entry matching the value, and map to the key.
use std::collections::HashMap;
fn find_key_for_value<'a>(map: &'a HashMap<i32, &'static str>, value: &str) -> Option<&'a i32> {
map.iter()
.find_map(|(key, &val)| if val == value { Some(key) } else { None })
}
fn main() {
let mut map = HashMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "c");
assert_eq!(find_key_for_value(&map, "a"), Some(&1));
assert_eq!(find_key_for_value(&map, "z"), None);
}
Note that this will only find the first matching value, if you want to find all matching values, you can use filter_map and collect them into a Vec:
use std::collections::HashMap;
fn find_keys_for_value<'a>(map: &'a HashMap<i32, &'static str>, value: &str) -> Vec<&'a i32> {
map.iter()
.filter_map(|(key, &val)| if val == value { Some(key) } else { None })
.collect()
}
fn main() {
let mut map = HashMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "c");
map.insert(4, "a");
let mut keys = find_keys_for_value(&map, "a");
keys.sort();
assert_eq!(keys, vec![&1, &4]);
}

Can not iterate over vector of structs: a collection of type std::vec::Vec<Foo> cannot be built from an iterator over elements of type &Foo [duplicate]

I am trying to convert a vector of &str pairs into a HashMap with the following code snippet:
use std::collections::HashMap;
fn main() {
let pairs = vec!(("foo", "bar"), ("toto", "tata"));
let map: HashMap<&str, &str> = pairs.iter().collect();
println!("{:?}", map);
}
However the compilation fails with this error:
<anon>:5:47: 5:56 error: the trait `core::iter::FromIterator<&(&str, &str)>` is not implemented for the type `std::collections::hash::map::HashMap<&str, &str>` [E0277]
<anon>:5 let map: HashMap<&str, &str> = pairs.iter().collect();
However if I add .cloned() before calling collect() everything works fine:
...
let map: HashMap<&str, &str> = pairs.iter().cloned().collect();
...
Even if I understand the error message (there is no implementation of the trait FromIterator<&(&str, &str)> for the type HashMap<&str, &str>) I do not understand where the type &(&str, &str) comes from (according to the method signature in the Rust documentation) and why calling cloned() fixes that problem.
The type &(&str, &str) comes from what iter() on a Vec returns:
fn iter(&self) -> Iter<T>
where Iter<T> implements Iterator<Item=&T>:
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T
...
}
In other words, iter() on a vector returns an iterator yielding references into the vector.
cloned() solves the problem because it is an iterator adapter which converts Iterator<Item=&T> to Iterator<Item=T> if T is cloneable. You can think of it as a shorthand for map(|v| v.clone()):
let v1: Vec<i32> = vec![1, 2, 3, 4];
let v2: Vec<_> = v1.iter().cloned().collect();
let v3: Vec<_> = v1.iter().map(|v| v.clone()).collect();
assert_eq!(v2, v3);
It happens that (&str, &str) is cloneable because each tuple component is also cloneable (all references are), so cloned() would return an object which implements Iterator<Item=(&str, &str)> - exactly what collect() needs to create a HashMap.
Alternatively, you can use into_iter() to get Iterator<Item=T> from Vec<T>, but then the original vector will be consumed:
use std::collections::HashMap;
fn main() {
let pairs = vec!(("foo", "bar"), ("toto", "tata"));
let map: HashMap<&str, &str> = pairs.into_iter().collect();
println!("{:?}", map);
}
The problem is that while the references may be copied, the tuples cannot.
However, if you don't need the pairs anymore, you can iterate by values:
use std::collections::HashMap;
fn main() {
let pairs = vec!(("foo", "bar"), ("toto", "tata"));
let map: HashMap<&'static str, &'static str> = pairs.into_iter().collect();
println!("{:?}", map);
}

Resources