'How to invert a `HashMap<String, MyEnum>`? (Error: "`FromIterator` not implemented for [pair]")
I'm trying to invert a HashMap<String, MyEnum>
in Rust, and getting an error:
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?
Solution 1:[1]
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();
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();
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()))
));
Solution 2:[2]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Neil |
Solution 2 | Jeremy Meadows |