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

时间:2018-06-24 21:04:41

标签: 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;
}

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,但是我无法计算出正确的组合/嵌套来获得想要的结果。

p.s。只是为了使这个有趣。这是对数据库的外部联接查询,因此Struct2可能没有任何Struct3元素(因此key3是Integer而不是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"

我希望得到类似以下内容的结果

[{
   "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"
            }]
}]

这是一个答案,但我不是超级粉丝:

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

}

预先感谢

斯图

1 个答案:

答案 0 :(得分:0)

在类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();
相关问题