将平展数据转换为嵌套层次结构



我有一个扁平化的数据结构(这实际上是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, .....);

我可以使用的工具是分组/映射/减少,但我无法找出正确的组合/嵌套来实现我想要的结果。

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

示例数据:

键 1 值
1 键 2 键 3 最终值 1 "值1" 2 3 "最终1" 1 "值1" 2 4 "最终2" 1 "值1" 3 空空 5 "值2" 6 7"最终3">

我期待如下结果

[{  "键 1" : 1,  "值 1" : "值 1",  "内部" : [ {  "键 2" : 2,  "内部" : [ { "键3" : 3, "最终值" : "final1"  }, { "键3" : 4,  "最终值" : "final2"  }], }, {  "键2" : 3,  "内部" : []  }], }, { "键1" : 5, "值 1" : "值 2", "内部" : [ {  "键2" : 6,  "内部" : [ { "键3" : 7, "最终值" : "final3" }] }]

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

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
.....

}

提前致谢

斯图

在类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 对象的示例。不过老派的循环。

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();

最新更新