Java 将展开数据转换为嵌套层次结构
我有一个扁平的数据结构(实际上是DB SQL查询的结果,因此会有大量重复数据),我想将其转换为继承权 输入结构: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
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();