使用 Stream API 时无法将 Collection<Integer> 转换为 int

Collection<Integer> cannot be converted to int while using Stream API

我想做一个 Map<Person, Double>,其中 Double 是存储在另一个 Map <String, Integer> 中的 Integer 值的平均值,它是流元素的字段之一.

public Map<Person,Double> totalScores(Stream<CourseResult> programmingResults) {
    return 
        programmingResults.collect(Collectors.groupingBy(
            CourseResult::getPerson,
// And there is a problem, I want to get values from `Map <String, Integer>` 
// and do the `averagingInt`, but only get 
//`Bad return type in lambda expression: 
// Collection<Integer> cannot be converted to int`

            Collectors.averagingInt(
                s -> s.getTaskResults().values()
            )
        ));
}

如何以正确的方式获取这些值?

我正在使用一些 类:

public class CourseResult {
    private final Person person;
    private final Map<String, Integer> taskResults;
    
    public CourseResult(final Person person, final Map<String, Integer> taskResults) {
        this.person = person;
        this.taskResults = taskResults;
    }
    
    public Person getPerson() {
        return person;
    }
    
    public Map<String, Integer> getTaskResults() {
        return taskResults;
    }
}

请注意 values()Collection<Integer>。你不能以此为平均值。您可以使用平面映射 Collector,将每组人扁平化为整数,而不是 CourseResult。之后就可以通过恒等函数做平均了。

return programmingResults.collect(
    Collectors.groupingBy(
        CourseResult::getPerson,
        Collectors.flatMapping(s->s.getTaskResults().values().stream(),
            Collectors.averagingInt(x -> x)
            )
    )
);

编辑:如果每个 Person 只有一个 CourseResult,那么您不需要 groupingBy。只需使用 toMap 并使用另一个流计算平均值。

return programmingResults.collect(
    Collectors.toMap(
        CourseResult::getPerson, 
        result -> result.getTaskResults().values()
            .stream().mapToInt(x -> x).average().orElse(0))
);

如果保证输入流包含 CourseResult 个具有唯一人员的实例(并且可能不需要任务结果的分组 + flatMapping),使用 toMap 可能就足够了收藏家:

public Map<Person,Double> totalScores(Stream<CourseResult> results) {
    return 
        results.collect(Collectors.toMap(
            CourseResult::getPerson,
            cr -> cr.getTaskResults().values() // Collection<Integer>
                .stream() // Stream<Integer>
                .collect(Collectors.averagingInt(Integer::intValue))
            )
        ));
}