【问题标题】:Java 8 Group by and append to a setJava 8 分组并附加到集合
【发布时间】:2019-09-03 00:04:35
【问题描述】:

我有一个函数返回一个Map<String, Set<String>>,Java 8 之前的代码:

Map<String, Set<String>> degreeMap = new HashMap<>();
for(Course  course : courses){
    Set<String> cList = degreeMap.get(course.getCourseLevel().toString());
    if(Objects.nonNull(cList)){
        cList.addAll(course.getMasterDegree()); //this is what i want to append to the old set
        degreeMap.put(course.getCourseLevel().toString(), cList);
    } else{
        degreeMap.put(course.getCourseLevel().toString(), new HashSet<>(course.getMasterDegree()));
    }
} 
return degreeMap;

返回课程级别的地图 -> 度数集。

例如,它读取所有课程并返回如下地图:

{"undergraduate" : ["BTech", "BSc", "BE"],
"masters": ["MTech", "MBA"],
"Executive": ["PGDBM", "EECP"]}

这是我的课程:

public class Course {
    private List<String> masterDegree;
    private CourseLevel courseLevel;
}

但我想用 Java 8 风格编写这段代码。为此,我尝试了这个:

Map<String, Set<String>> degreeMap = courses.stream().collect(
        Collectors.groupingBy(c -> c.getCourseLevel().toString(),
                Collectors.mapping(c -> c.getMasterDegree(), Collectors.toSet()))
);

这不起作用,我收到以下编译时错误:

不存在类型变量的实例,因此 List 符合 String 推断变量 T 具有不兼容的边界:等式约束:String 下界:List

任何建议,如何实现?

【问题讨论】:

  • 在我看来,您正在寻找与旧版本中的 Java-9 等效的 flatMapping
  • @GhostCat 尝试编辑问题以使其足够相关。希望现在清楚。
  • @Naman 感谢您解决了这场战斗:P
  • for(Course course : courses) degreeMap.computeIfAbsent(course.getCourseLevel() .toString(), x -&gt; new HashSet&lt;&gt;()) .addAll(course.getMasterDegree()); 顺便说一句,即使在您的 Java 8 之前的版本中,也没有理由在 addAll 之后再次将 put 同一个列表放入 Map

标签: java collections java-8 group-by collectors


【解决方案1】:

未经测试,但看起来,您正在寻找类似的东西:

    return courses.stream()
            .collect(Collectors.toMap(course -> course.getCourseLevel().toString(),
                    course -> new HashSet<>(course.getMasterDegree()),
                    (set1, set2) -> Stream.of(set1, set2)
                            .flatMap(Set::stream).collect(Collectors.toSet())));

【讨论】:

  • 在这种情况下,(set1, set2) -&gt; { set1.addAll(set2); return set1; } 显然是更可取的合并函数……
【解决方案2】:

我认为您不需要 lamda 表达式,您应该重构代码以使其清晰。

        // supposed to be initialied with non-empty values
        // Map<String, Set<String>> degreeMap = ...

        for(Course  course : courses){
            // something like below
            String key = course.getCourseLevel().toString();
            // degreeSet should not be null
            Set<String> degreeSet = course.getMasterDegree();

            // TODO: check nullable
            degreeSet.putAll(degreeMap.get(key));

            degreeMap.put(key, degreeSet);
        } 

        return degreeMap;

【讨论】:

    【解决方案3】:

    您可能对 Collectors.toMap() 方法感兴趣。

    这是一个你可能需要调整的例子,因为我没有测试它。

    Map<String, Set<String>> degreeMap = courses.stream()
        .collect(
            Collectors.toMap(
                item -> item.getCourseLevel().toString(), //your key mapping
                item -> item.getMasterDegree(), //your value mapping
                (oldValue, newValue) -> { //your process of aggregation
                    if (null == oldValue) {
                        return newValue;
                    } else {
                        oldValue.addAll(newValue);
                        return oldValue;
                    }
                },
                LinkedHashMap::new //your result initialiser
            )
        );
    

    另外,另一个提示:您不需要按键获取并检查是否为空,您可以在地图上使用 .compute()、.computeIfAbsent()、.computeIfPresent() 方法

    【讨论】:

      猜你喜欢
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-20
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多