I wrote this code for the ETL exercise on exercism.io. The basic idea is to take a BTreeMap with u32 keys and Vec<char> values and transform it into a BTreeMap with char keys and u32 values.
Original data:
- 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T",
- 2 points: "D", "G",
- 3 points: "B", "C", "M", "P",
- 4 points: "F", "H", "V", "W", "Y",
- 5 points: "K",
- 8 points: "J", "X",
- 10 points: "Q", "Z",
What I want after transformation:
- "a" is worth 1 point.
- "b" is worth 3 points.
- "c" is worth 3 points.
- "d" is worth 2 points.
- Etc.
I first did it in an imperative way like so: Playground
use std::collections::BTreeMap;
pub fn transform(h: &BTreeMap<i32, Vec<char>>) -> BTreeMap<char, i32> {
let mut result = BTreeMap::new();
for (&key, values) in h {
for v in values {
result.insert(v.to_ascii_lowercase(), key);
}
}
result
}
Then I translated it to a more functional way: Playground
use std::collections::BTreeMap;
pub fn transform(h: &BTreeMap<i32, Vec<char>>) -> BTreeMap<char, i32> {
h.iter().fold(BTreeMap::new(), |mut acc, (&key, values)| {
values.iter().map(char::to_ascii_lowercase).for_each(|v| { acc.insert(v, key); });
acc
})
}
Now, my question is, is the functional version the clearest I could've done, or is there a clearer functional way to do this?