【问题标题】:convert flattened data to nested hierarchy将展平数据转换为嵌套层次结构
【发布时间】:2018-06-24 21:04:41
【问题描述】:

我有一个扁平的数据结构(实际上是 DB SQL 查询的结果,因此会有很多重复数据),我想将其转换为层次结构。

输入结构:

class Data {
    int key1;
    String value1;
    int key2;
    Integer key3;
    String finalValue;
}

输出结构

class Struct1 {
    int key1;
    String value1;
    List<Struct2> inner;
}

class Struct2 {
    int key2;
    List<Struct3> inner;
}

class Struct3 {
    int key3;
    String finalValue;
}

所以.....

 List<Data> input = ....
 List<Struct1> results = input.stream().collect(groupingBy(x->x.key1, .....);

我可以使用的工具是 group/map/reduce,但我无法计算出正确的组合/嵌套来实现我想要的结果。

附言只是为了让这变得有趣。这是对数据库的外部联接查询,因此 Struct2 可能没有任何 Struct3 元素(因此 key3 是 Integer 而不是 int)

示例数据:

键 1 值 1 键 2 键 3 最终值 1“值1” 2 3“最终1” 1“价值1” 2 4“最终2” 1 "value1" 3 null null 5“值2” 6 7“最终3”

我希望得到类似下面的结果

[{ “key1”:1, “价值1”:“价值1”, “内部”:[{ “key2”:2, “内部”:[{ “key3”:3, “最终值”:“最终 1” }, { “key3”:4, “最终值”:“最终 2” }], }, { “key2”:3, “内部”:[] }], }, { “key1”:5, “价值1”:“价值2”, “内部”:[{ “key2”:6, “内部”:[{ “key3”:7, “最终值”:“最终 3” }] }]

这是一个答案,但我不是忠实粉丝:

Map<Long, Data> groupByKey1 = data.stream().collect(groupingBy(x->x.key1));
List<Struct1> result = groupByKey1.entrySet().stream().map(this::createStruct1).collect(toList());

Struct1 createStruct1(Entry<Long, List<Data>> item) {
    List<Struct2> struct2 = item.getValue().stream().collect(groupingBy(x->x.key2)).entrySet().stream().map(this::createStruct2).collect(toList());
    // create and return Struct1
    .....
 }

第二次尝试(我认为这是我正在寻找的答案)

Map<Long, Data> groupByKey1 = data.stream().collect(groupingBy(x->x.key1, collectingAndThen(toList(), this::createStruct1));

Struct1 createStruct1(List<Data> item) {
List<Struct2> struct2 = item.stream().collect(groupingBy(x->x.key2, collectingAndThen(toList(), this::createStruct2));
// create and return Struct1
.....

}

提前致谢

学习

【问题讨论】:

    标签: java java-stream


    【解决方案1】:

    在类Struct1 中创建一个构造函数,该构造函数获取一行的所有值,为其他类编写类似的构造函数,并从Struct1 构造函数中调用它们。完成后,编写正确的流应该很容易。

    public Struct1(int key1, String value1, int key2, Integer key3, String finalValue) {
       this.key1 = key1;
       this.value1 = value1;
    
       Struct3 str3 = new Struct3(key3, finalValue);
       Struct2 str2 = new Struct2(key2, str3);
    
       this.inner = new ArrayList<>();
       this.inner.add(str2);
    }
    

    这是一个处理创建和更新 Struct1 对象的示例。不过老派的 for 循环。

    Map<Integer, Struct1> cache = new HashMap<>();
    for (Data data: input) {
        Struct1 str1 = cache.get(data.key1);
        if (str1 == null) {
            str1 = new Struct1(data.key1, data.value1, data.key2, data.key3, data.finalValue);
            cache.put(str1.key1, str1);
         } else {
            str1.update(data.key2, data.key3, data.finalValue);
         }
     }
    
     List<Struct1> result = cache.values();
    

    【讨论】:

    • 这只会在 Struct1 中为我们提供一个 Struct2 实例,在示例数据中,Struct2 中有 2 个元素。 Struct1 和 Struct2 和 Struct3 之间是一对多的关系。如果我要遵循您的建议,那么 Struct2 构造函数将需要 Struct3 项的集合,而 Struct1 将需要 Struct2 项的集合
    • 然后将每个创建的 Struct1 对象添加到以 key1 为键的字典中,并使用更新方法补充 Struct1(和 Struct2)。这在传统循环中可能比使用流更容易处理。
    猜你喜欢
    • 1970-01-01
    • 2021-08-08
    • 2022-11-24
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多