[英]Complex aggregation using Java 8 streams
給定一個類項目:
public class Item {
private String field1;
private String field2;
private String field3;
private Integer field4;
// getters, constructor...
}
另一個類Group(field1和field2存儲Item中的等效字段):
public class Group {
private String field1;
private String field2;
}
我有一個List<Item>
,我需要將其聚合到以下結構的地圖中:
Map<Group, Map<Field3, List<Field4>>>
示例數據:
Field1 | Field2 | Field3 | Field4
------ | ------ | ------ | ------
"f1" | "f2" | "a" | 1
"f1" | "f2" | "a" | 2
"f1" | "f2" | "a" | 3
"f1" | "f2" | "b" | 4
"f1" | "f2" | "b" | 5
"f1" | "f2" | "c" | 6
"f1a" | "f2a" | "a" | 7
"f1a" | "f2a" | "a" | 8
預期結果如下:
Group(field1=f1a, field2=f2a)={b=[7, 8]}, Group(field1=f1, field2=f2)={a=[1, 2, 3], b=[4, 5], c=[6]}
到目前為止,我已經能夠通過Field1,Field2和Field3進行聚合,這樣我就有了以下結構(其中GroupEx
代表一個保存Field1,Field2和Field3的POJO):
Map<GroupEx, List<Field4>>
以這種方式聚合的代碼是:
Map<GroupEx, List<Integer>> aggregated = items.stream()
.collect(Collectors.groupingBy(item -> new GroupEx(x.getField1(), x.getField2(), x.getField3())
, Collectors.mapping(Item::getField4, Collectors.toList())));
我正努力讓語法正確,允許我按Field1和Field2分組,然后按照我需要的方式將Field3和Field4分組到地圖中。
“長手”語法是:
Map<Group<String, String>, Map<String, List<Integer>>> aggregated = new HashMap<>();
for (Item item : items) {
Group key = new Group(item.getField1(), item.getField2());
Map<String, List<Integer>> field3Map = aggregated.get(key);
if (field3Map == null) {
field3Map = new HashMap<>();
aggregated.put(key, field3Map);
}
List<Integer> field4s = field3Map.get(item.getField3());
if (field4s == null) {
field4s = new ArrayList<>();
field3Map.put(item.getField3(), field4s);
}
field4s.add(item.getField4());
}
有人能告訴我如何實現目標分組嗎?
這是下游收集器功能的便利之處。
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
...
List<Item> list = ....
Map<Group, Map<String, List<Integer>>> map =
list.stream().collect(groupingBy(i -> new Group(i.getField1(), i.getField2()),
groupingBy(Item::getField3, mapping(Item::getField4, toList()))));
首先,按照“ Group
字段對項目進行Group
(此時為“ Map<Group, List<Item>>
),然后將每個值(“ List<Item>
)再次映射到按地圖3分組的Map<Group, Map<Field3, List<Item>>
( Map<Group, Map<Field3, List<Item>>
)。
然后,您將第二個地圖中的值映射到field4,然后將它們收集到一個列表中,最后得到Map<Group, Map<Field3, List<Field4>>
。
根據您的輸入,它輸出:
{Group{field1='f1a', field2='f2a'}={a=[7, 8]}, Group{field1='f1', field2='f2'}={a=[1, 2, 3], b=[4, 5], c=[6]}}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.