 # Is this the FP way to do this?

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?

I would use `flat_map`.

``````pub fn transform(h: &BTreeMap<i32, Vec<char>>) -> BTreeMap<char, i32> {
h.iter().flat_map(|(&key, values)| {
values.iter().map(move |c| (c.to_ascii_lowercase(), key))
}).collect()
}
``````
3 Likes

Thanks, looks much better!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.