流 Java 8 api 中是否有 aggregateBy 方法?

2022-09-03 14:06:22

在Brian Goetz的这个非常有趣但已有一年历史的演示文稿中 - 在链接的幻灯片中,他提出了一个据说在Stream API中的方法,该方法应该将列表(?)的元素聚合到地图(给定默认的初始值和操作该值的方法(也适用于重复键) - 请参阅演示文稿中的下一张幻灯片)。aggregateBy()

显然,流 API 中没有这样的方法。有没有另一种方法可以在Java 8中做类似的事情?


答案 1

可以使用收集器类完成聚合操作。因此,在视频中,该示例等效于:

Map<String, Integer> map = 
    documents.stream().collect(Collectors.groupingBy(Document::getAuthor, Collectors.summingInt(Document::getPageCount)));

该方法将为您提供.现在,您必须使用下游收集器来求和与每个键关联的每个文档的所有页数。groupingByMap<String, List<Document>>List

这是通过向 提供下游收集器来完成的,该收集器是 ,从而得到一个 。groupingBysummingIntMap<String, Integer>


他们在文档中给出了基本相同的示例,他们按部门计算员工的工资总和。

我认为他们删除了此操作并创建了类,而是具有一个有用的类,该类包含许多您将常用的简化。Collectors


答案 2

假设我们有一个员工名单及其部门和薪水,我们希望每个部门支付的总工资。

有几种方法可以做到这一点,例如,您可以使用收集器来聚合每个部门的数据:toMap

  • 第一个参数是键映射器(聚合轴 = 部门),
  • 第二个是价值映射器(您要聚合的数据=工资),以及
  • 第三个是合并函数(您希望如何聚合数据=对值求和)。

例:

import static java.util.stream.Collectors.*;

public static void main(String[] args) {
  List<Person> persons = Arrays.asList(new Person("John", "Sales", 10000),
                                       new Person("Helena", "Sales", 10000),
                                       new Person("Somebody", "Marketing", 15000));

  Map<String, Double> salaryByDepartment = persons.stream()
          .collect(toMap(Person::department, Person::salary, (s1, s2) -> s1 + s2));
  System.out.println("salary by department = " + salaryByDepartment);
}

与流一样,有几种方法可以获得所需的结果,例如:

import static java.util.stream.Collectors.*;

Map<String, Double> salaryByDepartment = persons.stream()
        .collect(groupingBy(Person::department, summingDouble(Person::salary)));

作为参考,Person 类:

static class Person {
  private final String name, department;
  private final double salary;
  public Person(String name, String department, double salary) {
    this.name = name;
    this.department = department;
    this.salary = salary;
  }
  public String name() { return name; }
  public String department() { return department; }
  public double salary() { return salary; }
}

推荐