Reputation: 1826
I'm trying to create a vector of set (Vec<BTreeSet<char>>
) from Vec<Vec<char>>
. Here's my progress so far:
use std::collections::BTreeSet;
fn main() {
// The data
let transaction_list = [
vec!['A','B','C','D'],
vec!['B','B','C'],
vec!['A','B','B','D']
];
// Successfully created a set from the Vec of Vec. It contains unique chars
let item_set: BTreeSet<char> = transaction_list.iter().flat_map(|t| t).cloned().collect();
// Made the same Vec of Vec. Basically just experimenting with map and collect
let the_same_transaction_list: Vec<Vec<char>> = transaction_list.iter().map(|t| t ).cloned().collect::<Vec<_>>();
// ERROR
let transaction_set: Vec<BTreeSet<char>> = transaction_list
.iter()
.map(|t| t.iter().map(|t| t).cloned().collect() )
.cloned().collect::<Vec<_>>();
}
The error message was:
error: the trait `core::iter::FromIterator<char>` is not implemented for the type `&_` [E0277]
.map(|t| t.iter().map(|t| t).cloned().collect() )
^~~~~~~~~
help: see the detailed explanation for E0277
note: a collection of type `&_` cannot be built from an iterator over elements of type `char`
I haven't found the correct way to make a Vec<BTreeSet<char>>
out of Vec<Vec<char>>
. Here's the playground url: http://is.gd/WVONHY.
Upvotes: 5
Views: 2536
Reputation: 431809
The error message is a bit odd. Here's the solution:
let transaction_set: Vec<BTreeSet<_>> =
transaction_list
.iter()
.map(|t| t.iter().cloned().collect())
.collect();
The two main changes are:
map(|x| x)
is pointless. It is a no-op.cloned
. The result type of the map
call is already going to be a BTreeSet
. There's no need to then clone it again.The latter fixes your problem, so let's look at the definition:
fn cloned<'a, T>(self) -> Cloned<Self>
where Self: Iterator<Item=&'a T>,
T: 'a + Clone
To be able to call cloned
, the iterator Item
has to be a reference to something that is cloneable. However, you are trying to iterate over BTreeSet
s, which are not references. The compiler chooses to tell you that there's no way to collect
your inner iterator of char
into a &_
(a reference to some type), which would then satisfy the requirement to call cloned
. My guess is that the inner type has more wiggle-room than the type needed by collect
. If we rewrite the original code a bit to have a more definitive type on the inside:
let transaction_set: Vec<_> =
transaction_list
.iter()
.map(|t| -> BTreeSet<_> {t.iter().cloned().collect()})
.cloned().collect();
We get a different set of errors:
error: type mismatch resolving `<[closure...] as core::ops::FnOnce<(&collections::vec::Vec<char>,)>>::Output == &_`:
expected struct `collections::btree::set::BTreeSet`,
found &-ptr [E0271]
.cloned().collect();
^~~~~~~~
error: no method named `collect` found for type `core::iter::Cloned<core::iter::Map<core::slice::Iter<'_, collections::vec::Vec<char>>, [closure...]>>` in the current scope
.cloned().collect();
^~~~~~~~~
note: the method `collect` exists but the following trait bounds were not satisfied: `core::iter::Cloned<core::iter::Map<core::slice::Iter<'_, collections::vec::Vec<char>>, [closure...]>> : core::iter::Iterator`
Which helps highlight that the problem arises from the outer use of cloned
.
Upvotes: 4