financial_physician
financial_physician

Reputation: 1978

How to idiomatically filter on the uniqueness of an iterable of iterable types in Rust?

Let's say I have a vector of vectors vec_of_vecs = vec![vec![1,2],vec![1,3],vec![2,2],vec![2,3]]. What would be the idiomatic way of filtering out vec![2,2].

My attempt was this:

fn filter_out_duplicates(vec_of_vecs: Vec<Vec<u8>>) -> Vec<Vec<u8>> {
  vec_of_vecs
     .into_iter()
     .filter(all_unique)
     .collect()
}

pub fn all_unique<T>(iterable: T) -> bool
where
   T: IntoIterator,
   T::Item: Eq + Hash,
{
   let mut unique = HashSet::new();
   iterable.into_iter().all(|x| unique.insert(x))
}

But this gives me an error message I'm having a hard time decoding the error

the method `collect` exists for struct `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}>`, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
`<fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>} as std::ops::FnOnce<(&std::vec::Vec<u8>,)>>::Output = bool`
which is required by `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}>: std::iter::Iterator`
`fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}: std::ops::FnMut<(&std::vec::Vec<u8>,)>`
which is required by `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}>: std::iter::Iterator`
`std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}>: std::iter::Iterator`
which is required by `&mut std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}>: std::iter::Iterator`rustcE0599
filter.rs(15, 1): doesn't satisfy `_: std::iter::Iterator`

I believe what it's saying is that the iterator gets consumed in all_unique but from what I've read online, it doesn't seem like there's a great way to generalize my all_unique function to only consume references.

I could rewrite this using clone but I think there's a more idiomatic way to do it.

Upvotes: 1

Views: 201

Answers (1)

YthanZhang
YthanZhang

Reputation: 410

Update: checkout this answer for another question for why filter(all_unique) doesn't work.


all_unique doesn't need to consume a Vec, IntoIterator should be also implemented for the reference.

Here's a working example, the only real difference is instead of filter(all_unique), I used filter(|v| all_unique(v))

use std::hash::Hash;
use std::collections::HashSet;

fn filter_out_duplicates(vec_of_vecs: Vec<Vec<u8>>) -> Vec<Vec<u8>> {
  vec_of_vecs
     .into_iter()
     .filter(|v| all_unique(v))
     .collect()
}

pub fn all_unique<T>(iterable: T) -> bool
where
   T: IntoIterator,
   T::Item: Eq + Hash,
{
   let mut unique = HashSet::new();
   iterable.into_iter().all(|x| unique.insert(x))
}

Upvotes: 2

Related Questions