Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to invert a `HashMap<String, MyEnum>`? (Error: "`FromIterator` not implemented for [pair]")

Tags:

rust

I'm trying to invert a HashMap<String, MyEnum> in Rust, and getting an error:

  • Rust Playground instance

Code:

use std::collections::HashMap;

// Directive added because of this answer, which eliminated a couple of errors:
// https://github.com/rust-lang/rust/issues/22756#issuecomment-75715762
#[derive(Debug, PartialEq, Eq, Hash)]
enum MyEnum {
    Value1,
    Value2,
}

static MYMAP: HashMap<String, MyEnum> = HashMap::from([
    (String::from("value1"), MyEnum::Value1),
    (String::from("value1"), MyEnum::Value1),
]);

static MYMAP_INVERTED: HashMap<MyEnum, String> = HashMap::from([
    MYMAP.iter().map(|(k, v)| (v, k)).collect()
]);

Error:

error[E0277]: a value of type `(_, _)` cannot be built from an iterator over elements of type `(&MyEnum, &String)`
    --> src/main.rs:15:39
     |
15   |     MYMAP.iter().map(|(k, v)| (v, k)).collect()
     |                                       ^^^^^^^ value of type `(_, _)` cannot be built from `std::iter::Iterator<Item=(&MyEnum, &String)>`
     |
     = help: the trait `FromIterator<(&MyEnum, &String)>` is not implemented for `(_, _)`
note: required by a bound in `collect`

For more information about this error, try `rustc --explain E0277`.

How would you implement FromIterator for a pair?

like image 463
Neil Avatar asked Oct 16 '25 00:10

Neil


2 Answers

Your approach is ok, your types are wrong. Either you have references:

let my_map_inverted: HashMap<&MyEnum, &String> = my_map.iter()
    .map(|(k, v)| (v, k)).collect();

Playground

Or you Clone the keys and values:

let my_map_inverted: HashMap<MyEnum, String> = my_map.iter()
    .map(|(k, v)| (v.clone(), k.clone())).collect();

Playground

Then you have some other problems, like some calls cannot be used in static context, you can use once_cell for that:

use std::collections::HashMap;
use once_cell::sync::Lazy; // 1.10.0;

// Directive added because of this answer, which eliminated a couple of errors:
// https://github.com/rust-lang/rust/issues/22756#issuecomment-75715762
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
enum MyEnum {
    Value1,
    Value2,
}

static MYMAP: Lazy<HashMap<String, MyEnum>> = Lazy::new(
    || HashMap::from_iter([
        (String::from("value1"), MyEnum::Value1),
        (String::from("value1"), MyEnum::Value1),
]));

static MYMAP_INVERTED: Lazy<HashMap<MyEnum, String>> = Lazy::new(
    || HashMap::from_iter(MYMAP.iter().map(|(k, v)| (v.clone(), k.clone()))
));

Playground

like image 144
Netwave Avatar answered Oct 18 '25 14:10

Netwave


To swap the keys and values, you would be better off using the from_iter constructor since from can't take a Vec, and collect isn't sure what to do the way it is now. The code to do that would look like this, but you can't use methods like that in a static context, so that will require a refactor:

let MYMAP_INVERTED: HashMap<MyEnum, String> = HashMap::from_iter(
    MYMAP.iter().map(|(k, v)| (*v, k.clone()))
);

The *v and k.clone() are required because the map will return references to the data.

As for the static problem, your best bets would be either using the lazy_static crate or a SyncLazy from the standard library.

like image 25
Jeremy Meadows Avatar answered Oct 18 '25 15:10

Jeremy Meadows



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!