Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get first element from HashMap

I have a HashMap and need to get the first element:

type VarIdx = std::collections::HashMap<u16, u8>;

fn get_first_elem(idx: VarIdx) -> u16 {
    let it = idx.iter();
    let ret = match it.next() {
        Some(x) => x,
        None => -1,
    };
    ret
}

fn main() {}

but the code doesn't compile:

error[E0308]: match arms have incompatible types
 --> src/main.rs:5:15
  |
5 |       let ret = match it.next() {
  |  _______________^
6 | |         Some(x) => x,
7 | |         None => -1,
8 | |     };
  | |_____^ expected tuple, found integral variable
  |
  = note: expected type `(&u16, &u8)`
             found type `{integer}`
note: match arm with an incompatible type
 --> src/main.rs:7:17
  |
7 |         None => -1,
  |                 ^^

how can I fix it?

like image 872
Stepan Yakovenko Avatar asked Jul 19 '17 14:07

Stepan Yakovenko


People also ask

How do you get the first item on a Map?

To get the first element of a Map , use destructuring assignment, e.g. const [firstKey] = map. keys() and const [firstValue] = map. values() . The keys() and values() methods return an iterator object that contains the Map's keys and values.


1 Answers

There is no such thing as the "first" item in a HashMap. There are no guarantees about the order in which the values are stored nor the order in which you will iterate over them.

If order is important then perhaps you can switch to a BTreeMap, which preserves order based on the keys.

If you just need to get the first value that you come across, in other words any value, you can do something similar to your original code: create an iterator, just taking the first value:

fn get_first_elem(idx: VarIdx) -> i16 {
    match idx.values().next() {
        Some(&x) => x as i16,
        None => -1,
    }
}

The method values() creates an iterator over just the values. The reason for your error is that iter() will create an iterator over pairs of keys and values which is why you got the error "expected tuple".

To make it compile, I had to change a couple of other things: -1 is not a valid u16 value so that had to become i16, and your values are u8 so had to be cast to i16.

As another general commentary, returning -1 to indicate failure is not very "Rusty". This is what Option is for and, given that next() already returns an Option, this is very easy to accomplish:

fn get_first_elem(idx: VarIdx) -> Option<u8> {
    idx.values().copied().next()
}

The .copied() is needed in order to convert the &u8 values of the iterator into u8.

like image 137
Peter Hall Avatar answered Nov 01 '22 06:11

Peter Hall