Reputation: 11773
I have a function taking two borrowed arrays of a generic type T
, and I would like to create HashSet
s from those arrays so I can compare them.
I thought I would be able to do something like this:
pub fn sublist<T: PartialEq>(first_list: &[T], second_list: &[T]) -> bool {
let first_set: HashSet<T> = first_list.iter().collect();
let second_set: HashSet<T> = second_list.iter().collect();
first_set.is_subset(&second_set)
}
But I end up with the following errors:
a value of type `std::collections::HashSet<T>` cannot be built from an iterator over elements of type `&T`
value of type `std::collections::HashSet<T>` cannot be built from `std::iter::Iterator<Item=&T>`
help: the trait `std::iter::FromIterator<&T>` is not implemented for `std::collections::HashSet<T>`
Because of the first line in the error, I thought I might be able to solve it like this (I just changed the hashset type to references &T
):
pub fn sublist<T: PartialEq>(first_list: &[T], second_list: &[T]) -> bool {
let first_set: HashSet<&T> = first_list.iter().collect();
let second_set: HashSet<&T> = second_list.iter().collect();
first_set.is_subset(&second_set)
}
But then I see these errors:
the trait bound `T: std::cmp::Eq` is not satisfied
the trait `std::cmp::Eq` is not implemented for `T`
note: required because of the requirements on the impl of `std::cmp::Eq` for `&T`
note: required because of the requirements on the impl of `std::iter::FromIterator<&T>` for `std::collections::HashSet<&T>`
I don't understand how to create new data structures from references to an array. Is it the fact that these arrays are borrowed that is the problem, or is it ultimately the trait bound on PartialEq
that is the problem?
What if, for whatever reason, I can't modify the function signature, how can I use hashsets to compare the collections?
Upvotes: 0
Views: 2214
Reputation: 60493
To use HashSet
your function needs to have the Eq
and Hash
trait bounds:
use std::hash::Hash;
use std::collections::HashSet;
pub fn sublist<T: Eq + Hash>(first_list: &[T], second_list: &[T]) -> bool {
let first_set: HashSet<&T> = first_list.iter().collect();
let second_set: HashSet<&T> = second_list.iter().collect();
first_set.is_subset(&second_set)
}
If you only know that T
is PartialEq
, then you can implement it like so:
pub fn sublist<T: PartialEq>(first_list: &[T], second_list: &[T]) -> bool {
first_list.iter().all(|v| second_list.contains(v))
}
Other options include T: Ord
and use BTreeSet
.
Upvotes: 2