首页 > 解决方案 > 使用 Java 8 流将数据分组到地图中

问题描述

我想使用 Java 8 流 API 对数据进行分组。所有具有 parent_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}}.

简单的规则是:如果 parentId 不为空,则应将这些记录分组到一个列表中。并且此列表将被视为地图中的值。它的键是 parentId,它是实际的 id(列 id 的值,它不会为空。而 parentId 可以为空。如果一条记录的 parentId 为空,并且没有其他记录在其 parentId 列中具有其 ID,那么它将被视为具有键但值为空的单个对象。)

标签: javajava-8java-stream

解决方案


我认为你不能在单一流中做到这一点。

Map<Integer, String> roots = list.stream()
            .filter(myObject -> myObject.getParentId() == null)
            .collect(Collectors.toMap(MyObject::getId, MyObject::getName));

输出是其 id 和 name 的所有父级

{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());
    }
}

推荐阅读