我想使用Java8 streams API对数据进行分组。所有具有父_id的行都应分组在一起。下面是示例文本文件。结果应该是一个映射,其中id是一个整数,值是各自分组的行。例如,在下面的例子中,结果将是一个包含3个条目的映射。键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}}
。
简单的规则是:如果父母ID不是空的,这些记录应该被分组到一个列表中。这个列表将被视为map中的值。它的键将是父母ID,这是实际的id(列id的值,它不会为空。而父母ID可以为空。如果一条记录的父母ID为空,而其他记录的父母ID列中没有其他记录的ID,那么它将被视为一个具有键但为空值的单一对象。)
以下是一个更复杂的解决方案:
在第一个group By()
中,如果可用,则使用家长ID
,如果不可用,则使用id
:
Map<Integer, List<FileVO>> result = list.stream()
.collect(Collectors.groupingBy(f -> Optional.ofNullable(f.getParentId()).orElse(f.getId())));
这将创建属于一起的文件组:
{
1: [
{id: 1, name: "A", parentId: null},
{id: 2, name: "B", parentId: 1},
{id: 3, name: "C", parentId: 1}
],
4: [
{id: 4, name: "D", parentId : null}
],
5: [
{id: 5, name: "E", parentId : null},
{id: 6, name: "F", parentId : 5}
]
}
在第二步中,您将在每个组中找到父元素。如果您可以确保每个列表中的第一个元素都是父元素(就像在您的示例中,您可以使用以下内容:
Map<String, List<String>> result = list.stream()
.collect(Collectors.groupingBy(f -> Optional.ofNullable(f.getParentId()).orElse(f.getId())))
.entrySet().stream()
.collect(Collectors.groupingBy(e -> e.getValue().get(0).getName(),
Collectors.flatMapping(e -> e.getValue().stream().skip(1).map(FileVO::getName), Collectors.toList())));
这将只获取第一个元素(父元素)的名称,并映射除父元素本身之外的所有元素的名称。
如果您无法确保需要更通用的解决方案:
Map<String, List<String>> result = list.stream()
.collect(Collectors.groupingBy(f -> Optional.ofNullable(f.getParentId()).orElse(f.getId())))
.entrySet().stream()
.collect(Collectors.groupingBy(
e -> e.getValue().stream().filter(f -> f.getId() == e.getKey()).findAny().map(FileVO::getName).orElseThrow(),
Collectors.flatMapping(
e -> e.getValue().stream().filter(f -> f.getId() != e.getKey()).map(FileVO::getName),
Collectors.toList())));
这实际上是相同的,但是通过使用我们之前创建的映射条目的键来搜索父元素。
这两种解决方案都会将其作为示例数据返回:
{
A: [B, C],
D: [],
E: [F]
}
我认为你不能单流做。
Map<Integer, String> roots = list.stream()
.filter(myObject -> myObject.getParentId() == null)
.collect(Collectors.toMap(MyObject::getId, MyObject::getName));
out put的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 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转换为的实例(包括地图内容) 我应该怎么做才能使此代码可编译? 问题答案: 从Collectors.toMap(…)javadoc: 例如:
我正在使用我有一个类,如下所示: 现在我想做的是: 筛选出senderId无效的记录(使用映射) 下面是我的代码: 这给我带来了一个错误: 错误:(105,90)java:找不到适用于groupingBy(共享[…]的方法gMode,java。util。作用函数)方法java。util。流动收藏家。groupingBy(java.util.function.function)不适用(无法推断类型变
我正在尝试创建一个简单的解析util,它转换一个两列CSV文件并将其放入一个映射。 如您所见,我正在创建一个字符串流,用逗号分隔每一行,并将其转换为字符串数组,最后将键映射到索引0,将值映射到索引1。 出于某种原因,当我运行这个测试时,实际值为null。我排除了无效的文件路径,因为它在另一个单元测试中运行良好,并且键值出现在CSV中。我已经盯着它看了几个小时了,我想也许有人能指出我的错误。 此外,
我是Java8的新手,不能使用流将一个数组映射到另一个二维数组。 和包含键的第二个数组。 0表示:从模式中取0元素 1表示:从模式中取1元素,以此类推 从这两个数组中,我想生成另一个二维数组。在这种情况下,结果如下所示: 请帮忙
我试图翻译这个(简化)代码使用Java-8流: 以下是我尝试过的: 但以上给出了所有
我正在用Stream学习Java,我有一张