Build HashSet from a vector in Rust

Jared Beck picture Jared Beck · Oct 1, 2016 · Viewed 14.9k times · Source

I want to build a HashSet<u8> from a Vec<u8>. I'd like to do this

  1. in one line of code,
  2. copying the data only once,
  3. using only 2n memory,

but the only thing I can get to compile is this piece of .. junk, which I think copies the data twice and uses 3n memory.

fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
    let mut victim = vec.clone();
    let x: HashSet<u8> = victim.drain(..).collect();
    return x;
}

I was hoping to write something simple, like this:

fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
    return HashSet::from_iter(vec.iter());
}

but that won't compile:

error[E0308]: mismatched types
 --> <anon>:5:12
  |
5 |     return HashSet::from_iter(vec.iter());
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found &u8
  |
  = note: expected type `std::collections::HashSet<u8>`
  = note:    found type `std::collections::HashSet<&u8, _>`

.. and I don't really understand the error message, probably because I need to RTFM.

Answer

bluss picture bluss · Oct 1, 2016

Because the operation does not need to consume the vector¹, I think it should not consume it. That only leads to extra copying somewhere else in the program:

use std::collections::HashSet;
use std::iter::FromIterator;

fn hashset(data: &[u8]) -> HashSet<u8> {
    HashSet::from_iter(data.iter().cloned())
}

Call it like hashset(&v) where v is a Vec<u8> or other thing that coerces to a slice.

There are of course more ways to write this, to be generic and all that, but this answer sticks to just introducing the thing I wanted to focus on.

¹This is based on that the element type u8 is Copy, i.e. it does not have ownership semantics.