Transforming Structure of Collections

#1

Hi, thank you for clicking here!

My problem originated from an dilemma I had at work and I wondered how to solve it with Rust

I want to tranform my Data Structure in a more or less functional way.
I start out having a Vec<HashMap<String, T>> and I need a HashmapMap<String, Vec<T>>

Background:
The Entries of my List often share the same Key, and I want to accumulate all Entries with the Same Key in a List. That List should still be mapped by the key (in a HashMap)

I couldn’t find an elegant solution, this is how I solved it for now (Mind, this is kotlin Code, I will transform this into rust code below, but it might not compile):

val splitted: List<Map<String, T>> = ...
// Map from ID to List of Entities
val entities: MutableMap<String, MutableList<T>> = mapOf()

splitted.forEach { entries ->
     entries.forEach { key, value ->
        entities.getOrPut(key) { mutableListOf() }.add(value)
     }
}

Translation in Rust

let splitted: Vec<HashMap<String, T> = ...
let mut entites : Hashmap<String, Vec<T> = HashMap::new()

for entries in splitted {
    for (key, value) in entries {
        entities.entry(key).or_insert(Vec::new()).push(value)
    }
}

Hope you can help me out a little

#2

In general .flat_map(|_| inner_iterator) is a replacement for nested for loops.

.collect() makes data structures from iterators, and can make HashMap from tuples of (key, value).

But your current solution is fine. I don’t think you can make it any shorter or any faster.

Under the hood the for loop uses iterators, so it’s not very different from using an interator directly. The useful thing here is to move values without cloning them, and you’ve got that right.

1 Like
#3

for anyone interested, this problem was solved in kotlin over here

I will later try to translate this into rust

#4

The oft’-helpful itertools crate has a useful method here, allowing that to be

use itertools::Itertools;
use std::{collections::HashMap, hash::Hash};

pub fn demo<K: Hash + Eq, V>(x: Vec<HashMap<K, V>>) -> HashMap<K, Vec<V>> {
    x.into_iter().flatten().into_group_map()
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5435d00c103c9fdaa621b0007abf35b8

6 Likes
#5

Need to take a good look at itertools, looks quite promising! hank you for showing me such an expressive way to solve this., glad I know about this now