我看到了两种实现方式
如果您使用java-12 或更高版本,则可以使用Collectors::teeing
返回一个由两个下游收集器组合而成的收集器。
public static Map<Integer, List<Double>> averageInt(List<Student> students) {
return students.stream()
.collect(Collectors.groupingBy(
Student::getCourse,
Collectors.teeing(
Collectors.teeing(
Collectors.averagingInt(Student::getEngGrade),
Collectors.averagingInt(Student::getMathGrade),
(englishAverage, mathAverage) -> {
List<Double> averages = new ArrayList<>();
averages.add(englishAverage);
averages.add(mathAverage);
return averages;
}
),
Collectors.averagingInt(Student::getPhysicGrade),
(averages, physicsAverage) -> {
averages.add(physicsAverage);
return averages;
}
)
));
}
它给出了以下结果
public static void main(String[] args) {
Student studentOne = new Student(1, 5, 1, 1);
Student studentTwo = new Student(1, 1, 9, 2);
Student studentThree = new Student(1, 2, 9, 3);
Student studentFour = new Student(2, 5, 6, 4);
Student studentFive = new Student(2, 8, 1, 5);
Student studentSix = new Student(3, 3, 6, 0);
Student studentSeven = new Student(3, 5, 7, 7);
Student studentEight = new Student(3, 3, 6, 8);
Student studentNine = new Student(3, 4, 1, 9);
Student studentTen = new Student(4, 9, 1, 0);
List<Student> students = List.of(studentOne, studentTwo, studentThree, studentFour, studentFive, studentSix, studentSeven, studentEight, studentNine, studentTen);
System.out.println(averageInt(students));
}
结果
{
1 = [
6.333333333333333,
2.6666666666666665,
2.0
],
2 = [
3.5,
6.5,
4.5
],
3 = [
5.0,
3.75,
6.0
],
4 = [
1.0,
9.0,
0.0
]
}
使用客户收集器
但是,如果您更喜欢使用客户 Collector,以下是实现此目的的方法。为了方便起见,我在这里选择使用Map 而不是List,但是您当然也可以使用List 而不会改变此方法的本质
public static Map<Integer, Map<GradeType, Double>> averageInt(List<Student> students) {
return students.stream()
.collect(Collectors.groupingBy(
Student::getCourse,
new CustomCollector(Map.of(
GradeType.MATH, Student::getMathGrade,
GradeType.ENGLISH, Student::getEngGrade,
GradeType.PHYSICS, Student::getPhysicGrade
))
));
}
private enum GradeType {
MATH, ENGLISH, PHYSICS
}
private static class CustomCollector implements Collector<Student, Map<GradeType, List<Double>>, Map<GradeType, Double>> {
private final Map<GradeType, Function<Student, Integer>> functionsPerGradeType;
public CustomCollector(Map<GradeType, Function<Student, Integer>> functionsPerGradeType) {
this.functionsPerGradeType = functionsPerGradeType;
}
@Override
public Supplier<Map<GradeType, List<Double>>> supplier() {
return HashMap::new;
}
@Override
public BiConsumer<Map<GradeType, List<Double>>, Student> accumulator() {
return (map, student) -> {
for (Map.Entry<GradeType, Function<Student, Integer>> entry : functionsPerGradeType.entrySet()) {
GradeType gradeType = entry.getKey();
Double gradeForStudent = entry.getValue().apply(student).doubleValue();
map.computeIfAbsent(gradeType, gt -> new ArrayList<>());
map.get(gradeType).add(gradeForStudent);
}
};
}
@Override
public BinaryOperator<Map<GradeType, List<Double>>> combiner() {
return (mapOne, mapTwo) -> {
mapOne.forEach((k, v) -> {
mapTwo.merge(k, v, (listOne, listTwo) -> {
listOne.addAll(listTwo);
return listOne;
});
});
return mapTwo;
};
}
@Override
public Function<Map<GradeType, List<Double>>, Map<GradeType, Double>> finisher() {
return map -> {
Map<GradeType, Double> finishedMap = new HashMap<>();
for (var entry : map.entrySet()) {
GradeType gradeType = entry.getKey();
double gradeTypeAverage = entry.getValue().stream().mapToDouble(x -> x).average().orElse(0d);
finishedMap.put(gradeType, gradeTypeAverage);
}
return finishedMap;
};
}
@Override
public Set<Characteristics> characteristics() {
return Set.of(UNORDERED);
}
}
提供以下结果
{1={PHYSICS=2.0, ENGLISH=6.333333333333333, MATH=2.6666666666666665}, 2={PHYSICS=4.5, ENGLISH=3.5, MATH=6.5}, 3={PHYSICS=6.0, ENGLISH=5.0, MATH=3.75}, 4={PHYSICS=0.0, ENGLISH=1.0, MATH=9.0}}