1

我正在尝试将平面结构变成如下所示:

let flat = vec![
    Foo {
        a: "abc1".to_owned(),
        b: "efg1".to_owned(),
        c: "yyyy".to_owned(),
        d: "aaaa".to_owned(),
    },
    Foo {
        a: "abc1".to_owned(),
        b: "efg2".to_owned(),
        c: "zzzz".to_owned(),
        d: "bbbb".to_owned(),
    }];

通过serde_json看起来像这样的嵌套 JSON 对象:

{
    "abc1": {
        "efg1": {
            "c": "hij1",
            "d": "aaaa", 
        },
        "efg2": {
            "c": "zzzz",
            "d": "bbbb", 
        },
    }
}

b保证值在数组中是唯一的)

如果我只需要一层,我会做这样的事情:

let map = flat.into_iter().map(|input| (input.a, NewType {
    b: input.b,
    c: input.c,
    d: input.d,
})).collect::<Hashmap<String, NewType>>();

let out = serde_json::to_string(map).unwrap();

然而,这似乎并没有扩展到多层(即(String, (String, NewType))不能收集到Hashmap<String, Hashmap<String, NewType>>

在将条目转换为 json 之前,有没有比手动循环并将条目插入哈希映射更好的方法?

4

2 回答 2

1

Amap将保留数据的形状。那不是你想要的;转换后数据的基数发生了变化。所以仅仅一个map是不够的。

相反, afold会做:您从一个空的 开始HashMap,并在您遍历集合时填充它。但在这种情况下,它几乎不比循环更具可读性。我发现 amultimap在这里非常有用:

use multimap::MultiMap;
use std::collections::HashMap;

struct Foo {
    a: String,
    b: String,
    c: String,
    d: String,
}

#[derive(Debug)]
struct NewFoo {
    c: String,
    d: String,
}

fn main() {
    let flat = vec![
        Foo {
            a: "abc1".to_owned(),
            b: "efg1".to_owned(),
            c: "yyyy".to_owned(),
            d: "aaaa".to_owned(),
        },
        Foo {
            a: "abc1".to_owned(),
            b: "efg2".to_owned(),
            c: "zzzz".to_owned(),
            d: "bbbb".to_owned(),
        },
    ];
    let map = flat
        .into_iter()
        .map(|e| (e.a, (e.b, NewFoo { c: e.c, d: e.d })))
        .collect::<MultiMap<_, _>>()
        .into_iter()
        .map(|e| (e.0, e.1.into_iter().collect::<HashMap<_, _>>()))
        .collect::<HashMap<_, _>>();
    println!("{:#?}", map);
}
于 2019-09-16T09:41:38.587 回答
0

如果您需要做一些自定义来展平/合并您的Foo结构,您可以使用以下内容将其转换为 rust 代码中的 json 值:

   let mut root: Map<String, Value> = Map::new();
   for foo in flat.into_iter() {
       let b = json!({ "c": foo.c, "d": foo.d });
       if let Some(a) = root.get_mut(&foo.a) {
           if let Value::Object(map) = a {
                map.insert(foo.b, b);
           }
       } else {
           root.insert(foo.a, json!({foo.b: b}));
       }
   };

链接到游乐场

于 2019-09-18T02:12:29.807 回答