我想使用 Java 8 流 API 对数据进行分组。所有具有parent_id 的行都应该分组在一起。以下是示例文本文件。结果应该是一个映射,其中 id 将是整数,值将是相应的分组行。例如,在下面的情况下,结果将是包含 3 个条目的 map 。键 1 有 2 个值,键 2 无值,键 3 有 1 个值。
id name parent_id
1 A (null)
2 B 1
3 C 1
4 D (null)
5 E (null)
6 F 5
代码片段是:
Map<String, List<FileVO>> map= list.stream()
.collect(groupingBy(FileVO::getParentId, toList()));
输出可以类似于:{A,{B,C}}, {D,{}},{E,{F}}
。
简单的规则是:当parentId不为空时,这些记录应该被分组到一个列表中。这个列表将被视为 map 中的值。它的键是parentId,它是实际的id(列id的值,它不会为空。而parentId可以为空。如果一条记录的parentId为空,并且没有其他记录在其parentId列中具有其Id,那么它将被视为具有键但为空值的单个对象。)
最佳答案
我认为你不能在单流中做到这一点。
Map<Integer, String> roots = list.stream()
.filter(myObject -> myObject.getParentId() == null)
.collect(Collectors.toMap(MyObject::getId, MyObject::getName));
输出通过其 id 和名称都是父级
{1=A, 4=D, 5=E}
和
Map<Integer, List<String>> groupByParentId = list.stream()
.filter(myObject -> myObject.getParentId() != null)
.collect(Collectors.groupingBy(MyObject::getParentId,
Collectors.mapping(MyObject::getName, toList())));
输出按parentId分组
{1=[B, C], 5=[F]}
最后一步是:
roots.forEach((k,v)->map.put(v,groupByParentId.getOrDefault(k,new ArrayList<>())));
流版本更新:复杂度为 O(n^2)
list.stream()
.filter(myObject -> myObject.getParentId() == null)
.collect(Collectors.toMap(MyObject::getName, MyObject::getId))
.forEach((k, v) -> map.put(k, list.stream()
.filter(myObject -> myObject.getParentId() == v)
.map(MyObject::getName)
.collect(Collectors.toList())));
或者你也可以使用像这样的非流方式:(个人更喜欢非流版本)
注意:这样根就是Map<String,Integer> roots
String root = "";
for (MyObject myObject : list) {
if (myObject.getParentId() == null) {
root = myObject.getName();
map.put(root, new ArrayList<>());
}
if (roots.get(root).equals(myObject.getParentId())){
map.computeIfAbsent(root, k -> new ArrayList<>()).add(myObject.getName());
}
}
关于java - 使用 Java 8 流将数据分组到映射中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57101998/