I want to represent a table of data in the memory like the following:
| USD | EUR | -----+-----+-----+ John | 100 | 50 | -----+-----+-----+ Tom | 300 | 200 | -----+-----+-----+ Nick | 200 | 0 | -----+-----+-----+
There is a known set of people, each of them owns some currency.
And I have the following enums:
enum Person { John, Tom, Nick } enum Currency { USD, EUR }
I'd like to encode this data as 2D array, and it would be cool to be able to index array elements not by usize
but by enum
. E.g.:
data[Person::John][Currency::USD] = 100;
Is it possible to do with arrays and enums in Rust? Or is there any other data structure that would serve for this?
I am aware of HashMap
, but it's not exactly what I want because:
HashMap
works on the heap (what makes it much slower than regular stack allocated array)
HashMap
gives me no guarantee that item exist. E.g. every time I want to get something I have to unwrap it and handle None
case, what is not very handy in comparison with usage of normal array.
This is different from How do I match enum values with an integer? because I am not interested in converting enum to usize
; I just want a handy way to access array/map items by enum.
ljedrz provided a good solution. Another way to approach the problem is to use existing crate enum-map.
Add the following to your Cargo.toml
:
[dependencies] enum-map = "*" enum-map-derive = "*"
Then, in src/main.rs
:
extern crate enum_map; #[macro_use] extern crate enum_map_derive; #[derive(Debug, EnumMap)] enum Person { John, Tom, Nick } #[derive(Debug, EnumMap)] enum Currency { USD, EUR } use enum_map::EnumMap; use Person::*; use Currency::*; fn main() { // Create 2D EnumMap populated with f64::default(), which is 0.0 let mut table : EnumMap<Person, EnumMap<Currency, f64>> = EnumMap::default(); table[John][EUR] = 15.25; println!("table = {:?}", table); println!("table[John][EUR] = {:?}", table[John][EUR]); }
The output:
table = EnumMap { array: [EnumMap { array: [0, 15.25] }, EnumMap { array: [0, 0] }, EnumMap { array: [0, 0] }] } table[John][EUR] = 15.25
If you need this to be implemented using arrays, this isn't as straightforward as it might seem.
In order to be able to contain both of these pieces of information in an array (to be able to index by them), you first need to combine them in a single type, e.g. in a struct:
struct Money([(Currency, usize); 2]); struct PersonFinances { person: Person, money: Money }
Then, if you want to be able to index the table, you will need to wrap it in your own type so that you can implement the Index
trait for it:
use std::ops::Index; struct Table([PersonFinances; 3]); impl Index<(Person, Currency)> for Table { type Output = usize; fn index(&self, idx: (Person, Currency)) -> &Self::Output { &self .0 .iter() .find(|&pf| pf.person == idx.0) // find the given Person .expect("given Person not found!") .money .0 .iter() .find(|&m| m.0 == idx.1) // find the given Currency .expect("given Currency not found!") .1 } }
Then you can index the Table
by a Person
, Currency
pair:
table[(Tom, EUR)]
Rust playground link to the whole code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With