Get HashSet as value from HashMap in Rust - rust

How can I get the value of a HashMap, which is a HashSet in Rust?
Suppose I have ...
#[derive(PartialEq, Eq, Hash)]
struct A {
name: String,
}
fn main() {
let x: HashMap<i32, HashSet<A>> = HashMap::new();
let y: HashSet<A> = x.values().clone().collect();
}
This gives me the following compiler error ...
a value of type HashSet<A> cannot be built from an iterator over elements of type &HashSet<A>
the trait FromIterator<&HashSet<A>> is not implemented for HashSet<A>
the trait FromIterator<T> is implemented for HashSet<T, S>rustcE0277
iterator.rs(1832, 19): required by a bound in collect

It won't be single HashSet it would be collection of HashSet that's why you are getting the error
let x: HashMap<i32, HashSet<A>> = HashMap::new();
let y: Vec<&HashSet<A>> = x.values().clone().collect();
Playground
If you want to create a single HashSet<A> from HashMap<i32, HashSet<A>> values one of doing is as below:
let z: HashSet<&A> = x.values().clone().fold(HashSet::new(), |mut accum, item| {
accum.extend(item);
accum
});
Playground

Related

I can't build a value of type `Vec<B> from an iterator over elements of type `Vec<B>`

The code :
#[derive(Clone)]
pub struct A{
pub a: Vec<B>
}
#[derive(Clone)]
pub struct B {
pub b: Vec<C>
}
#[derive(Clone)]
pub struct C{
pub c :i32
}
fn main() {
let c= C{c :1};
let b = B{b : vec![c]};
let a = A{a : vec![b]};
let va = vec![a];
let ret=va.iter().map(|x| x.a.clone()).collect::<Vec<B>();;
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2219e3297bc28358f9f7ec532f2e5707
return this error:
error[E0277]: a value of type Vec<B> cannot be built from an iterator over elements of type Vec<B>
--> src/main.rs:20:44
|
20 | let ret=va.iter().map(|x| x.a.clone()).collect::<Vec>();;
| ^^^^^^^ value of type Vec<B> cannot be built from std::iter::Iterator<Item=Vec<B>>
|
= help: the trait FromIterator<Vec<B>> is not implemented for Vec<B>
I don't understand
https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-FromIterator%3CT%3E
says that vec implement From Iterator without condition on T
The error message means the element yielded from the iterator is of Vec<B> and therefore cannot be collected to form a list of Vec<B>.
It can be fixed by either changing the target type to Vec<Vec<B>>:
let ret=va.iter().map(|x| x.a.clone()).collect::<Vec<Vec<B>>>();
Or flattening the elements:
let ret=va.iter().flat_map(|x| x.a.clone()).collect::<Vec<B>>();
Playground

Collect vector of borrowed values into vec of borrowed trait

Is it possible to collect a Vec<&dyn Trait> from an iterator of values implementing Trait?
Here is an example, based on the Vector of objects belonging to a trait question:
trait Animal {
fn make_sound(&self) -> String;
}
struct Dog;
impl Animal for Dog {
fn make_sound(&self) -> String {
"woof".to_string()
}
}
fn main() {
let dogs = [Dog, Dog];
let v: Vec<&dyn Animal> = dogs.iter().collect();
for animal in v.iter() {
println!("{}", animal.make_sound());
}
}
this fails with error[E0277]: a value of type "Vec<&dyn Animal>" cannot be built from an iterator over elements of type &Dog`
however, if you use push the dogs individually into the vec (like in the answer to the original question) it works without issues.
let dog1: Dog = Dog;
let dog2: Dog = Dog;
let v: Vec<&dyn Animal> = Vec::new();
v.push(&dog1);
v.push(&dog2);
In order to collect an Iterator of a struct into a Vector of a trait that gets implemented by the Struct, it is possible to use the map method of the iterator to cast the borrowed struct into a borrowed trait.
let dogs = [Dog, Dog];
let v: Vec<&dyn Animal> = dogs.iter().map(|a| a as &dyn Animal ).collect();
See this playground for more info.

Why does an Iterator trait object referring to a sibling field fail to compile when the concrete type works?

I'd like to have an iterator that points into a Vec of the same struct.
The following works fine (playground):
struct Holder1<'a> {
vec: Vec<i32>,
iterator: Option<Box<std::slice::Iter<'a, i32>>>,
}
fn holder1_test() {
let vec = vec![1, 2, 3, 4];
let mut holder = Holder1 {
vec,
iterator: None,
};
let iterator: Box<std::slice::Iter<'_, i32>> = Box::new(holder.vec.iter());
holder.iterator = Some(iterator);
for iter_elem in holder.iterator.as_mut().unwrap() {
println!("iter: {}", iter_elem);
}
}
(I know the Box isn't needed here, I just wanted to keep this as close as possible to the next code snippet.)
I'd like to use a trait object, dyn Iterator, instead of the concrete type. I've slightly modified the example from above for that (playground):
struct Holder2<'a> {
vec: Vec<i32>,
iterator: Option<Box<dyn Iterator<Item = &'a i32>>>,
}
fn holder2_test() {
let vec = vec![1, 2, 3, 4];
let mut holder = Holder2 {
vec,
iterator: None,
};
let iterator: Box<dyn Iterator<Item = &'_ i32>> = Box::new(holder.vec.iter());
holder.iterator = Some(iterator);
for iter_elem in holder.iterator.as_mut().unwrap() {
println!("iter: {}", iter_elem);
}
}
This fails to compile:
error[E0597]: `holder.vec` does not live long enough
--> src/lib.rs:12:64
|
12 | let iterator: Box<dyn Iterator<Item = &'_ i32>> = Box::new(holder.vec.iter());
| ^^^^^^^^^^ borrowed value does not live long enough
...
18 | }
| -
| |
| `holder.vec` dropped here while still borrowed
| borrow might be used here, when `holder` is dropped and runs the destructor for type `Holder2<'_>`
What makes the second example so different to the first example that causes the compilation failure? Both iterators point to an element in the Vec of the same struct - so what's the conceptual difference here? Is there a way to get this to work with trait objects?
I'm aware that using an index instead of an iterator would solve this, but I'm rather interested in the underlying reasons of why this doesn't work.

How can I construct and pass an iterator of iterators?

I am trying to grok Rust by implementing simple algorithms in it. I managed to make a generic merge_sorted, which ended up having the following signature:
fn merge_sorted<IL, ILL, I: Ord>(mut arrays: ILL) -> Vec<I>
where
IL: Iterator<Item = I>,
ILL: Iterator<Item = IL>,
{
// ...
}
This seems to be compiling on its own. The signature makes sense to me, as the function consumes the top-level iterator, and all the iterators it returns too. However, I am unable to construct a valid value to pass to this function:
fn main() {
let v1 = vec![1, 2];
let vectors = vec![v1.iter()];
merge_sorted(vectors.iter());
}
As expected, vectors in this sample has the type:
std::vec::Vec<std::slice::Iter<'_, i32>>
This is the error message I get:
error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
--> src\main.rs:58:5
|
58 | merge_sorted(vectors.iter());
| ^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
note: required by `merge_sorted`
Where does the & come from?
Vec::iter borrows the items it contains, so you are iterating over borrowed iterators (&std::slice::Iter) that do not implement Iterator. To consume a vector in order to have the ownership of the items, you must call Vec::into_iter:
fn main() {
let v1 = vec![1, 2];
let vectors = vec![v1.iter()]; // You can use `into_iter` there to iterate over ints.
merge_sorted(vectors.into_iter());
}
You can also require IntoIterators that can make easier the usage of your API:
fn merge_sorted<IterT, IterIterT, T: Ord>(mut arrays: IterIterT) -> Vec<T>
where
IterT: IntoIterator<Item = T>,
IterIterT: IntoIterator<Item = IterT>,
{
panic!();
}
fn main() {
let v1 = vec![1, 2];
let vectors = vec![v1];
merge_sorted(vectors);
}

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