Home > Back-end >  Collection<Integer> cannot be converted to int while using Stream API
Collection<Integer> cannot be converted to int while using Stream API

Time:11-06

I want to do a Map<Person, Double>, where Double is average of Integer values that is stored in another Map <String, Integer> which is one of the fields of stream's elements.

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

How can I get these values in the right way?

There's some of the classes I'm using:

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;
    }
}

CodePudding user response:

Note that values() is a Collection<Integer>. You can't average by that. You can use a flat-mapping Collector, to flatten each group of persons to just integers, rather than CourseResult. After that, you can do an average by the identity function.

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

Edit: If there is only one CourseResult per Person, then you don't need groupingBy. Just use toMap and calculate the average using another stream.

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

CodePudding user response:

If it is guaranteed that the input stream contains CourseResult instances which have unique persons (and grouping flatMapping of the task results may not be needed), it may be sufficient to use toMap collector:

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))
            )
        ));
}
  • Related