0

I want to group a vector by key when the key is a vector.

struct Document {
    categories: Vec<String>,
    body: String
}
let docs = vec![
    Document {categories: ["rust".to_string(), body: "doc1".to_string()]},
    Document {categories: ["clojure".to_string()], body: "doc2".to_string()},
    Document {categories: ["java".to_string()], body: "doc3".to_string()},
    Document {categories: ["rust".to_string(), "clojure".to_string], body: "doc4".to_string()}
];

I want to return like below (category_key, documents)

"rust" => [doc1, doc4]  
"clojure" => [doc2, doc4]  
"java" => [doc3]
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Linca
  • 51
  • 6

1 Answers1

3

I'm a novice at Rust and this was a challenge for me

use std::collections::HashMap;

let result = docs.iter().fold(
    HashMap::new(),
    |mut init: HashMap<String, Vec<String>>, ref item| {
        for category in &item.categories {
            let item_body = item.body.clone();

            let new_vector: Vec<String> = init
                .remove(category)
                .map(|mut val| {
                    val.push(item_body.clone());
                    val
                })
                .unwrap_or(vec![item_body.clone()])
                .to_vec();
            init.insert(category.clone(), new_vector);
        }

        init
    },
);

I'm sure this code can be simplified.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
MrFirelord
  • 128
  • 6
  • 1
    [How to lookup from and insert into a HashMap efficiently?](https://stackoverflow.com/q/28512394/155423) – Shepmaster Jun 09 '19 at 14:03
  • 1
    Your `ref` is unneeded; you should use `unwrap_or_else`; there's no apparent reason to do any cloning. [How I'd write it](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2f2f1aa1b0f239ed08f34018f2f544d1) – Shepmaster Jun 09 '19 at 14:09
  • Perfect! Thanks a lot. – MrFirelord Jun 09 '19 at 15:27