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

Java 将展开数据转换为嵌套层次结构,java,java-stream,Java,Java Stream,我有一个扁平的数据结构(实际上是DB SQL查询的结果,因此会有大量重复数据),我想将其转换为继承权 输入结构: class Data { int key1; String value1; int key2; Integer key3; String finalValue; } 产出结构 class Struct1 { int key1; String value1; List<Struct2> inner; } c

我有一个扁平的数据结构(实际上是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;
}
类结构1{
int键1;
字符串值1;
内部列表;
}
类结构2{
int键2;
内部列表;
}
类结构3{
int键3;
字符串最终值;
}
所以

 List<Data> input = ....
 List<Struct1> results = input.stream().collect(groupingBy(x->x.key1, .....);
列表输入=。。。。
列表结果=input.stream().collect(groupingBy(x->x.key1,…);
我可以使用的工具是group/map/reduce,但我无法计算出正确的组合/嵌套来实现我想要的结果

p、 这是一个到数据库的外部连接查询,因此Struct2可能没有任何Struct3元素(因此为什么key3是整数而不是int)

示例数据:

key1 value1 key2 key3 finalValue 1 "value1" 2 3 "final1" 1 "value1" 2 4 "final2" 1 "value1" 3 null null 5 "value2" 6 7 "final3" 键1值1键2键3最终值 1“值1”2 3“最终值1” 1“值1”2 4“最终值2” 1“value1”3空 5“值2”6 7“最终值3” 我期望得到如下结果

[{ "key1" : 1, "value1" : "value1", "inner" : [ { "key2" : 2, "inner" : [ { "key3" : 3, "finalValue" : "final1" }, { "key3" : 4, "finalValue" : "final2" }], }, { "key2" : 3, "inner" : [] }], }, { "key1" : 5, "value1" : "value2", "inner" : [ { "key2" : 6, "inner" : [ { "key3" : 7, "finalValue" : "final3" }] }] [{ “关键1”:1, “value1”:“value1”, “内部”:[{ “关键2”:2, “内部”:[{ “关键3”:3, “最终价值”:“最终1” }, { “关键3”:4, “最终价值”:“最终2” }], }, { “关键2”:3, “内部”:[] }], }, { “关键1”:5, “value1”:“value2”, “内部”:[{ “键2”:6, “内部”:[{ “关键3”: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 groupByKey1=data.stream().collect(groupingBy(x->x.key1));
List result=groupByKey1.entrySet().stream().map(this::createStruct1.collect(toList());
Struct1 createStruct1(条目项){
List struct2=item.getValue().stream().collect(groupingBy(x->x.key2)).entrySet().stream().map(this::createStruct2.collect(toList());
//创建并返回Struct1
.....
}
第二次尝试(我认为这是我正在寻找的答案)

Map groupByKey1=data.stream().collect(groupingBy(x->x.key1,collectingAndThen(toList(),this::createStruct1));
Struct1 createStruct1(列表项){
List struct2=item.stream().collect(groupingBy(x->x.key2,collectingAndThen(toList(),this::createStruct2));
//创建并返回Struct1
.....
}

提前谢谢


Stu

在类
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);
}
公共结构1(int-key1、字符串值1、int-key2、整数键3、字符串最终值){ 此参数为0.key1=key1; 此值为1.value1=value1; Struct3 str3=新的Struct3(键3,最终值); Struct2 str2=新的Struct2(键2,str3); this.inner=新的ArrayList(); this.internal.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();
Map cache=newhashmap();
用于(数据:输入){
Struct1 str1=cache.get(data.key1);
如果(str1==null){
str1=新结构1(data.key1、data.value1、data.key2、data.key3、data.finalValue);
cache.put(str1.key1,str1);
}否则{
str1.更新(data.key2、data.key3、data.finalValue);
}
}
列表结果=cache.values();

这将只为我们提供Struct1中Struct2的一个实例,在示例数据中,Struct2中有两个元素。Struct1之间是一种一对多的关系,Struct2和Struct3之间也是如此。如果我遵循您的建议,那么Struct2构造函数将需要Struct3项的集合,Struct1将需要Struct2项的集合然后将每个创建的Struct1对象添加到以key1为键的字典中,并使用更新方法补充Struct1(和Struct2)。这可能在传统循环中比使用流更容易处理。
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();