Java 8 Streams API:对流进行分组和分区

这篇文章展示了如何使用Streams API中可用的Collectors将具有groupingBy的流元素和具有partitioningBy的流元素进行groupingBy

考虑一系列Employee对象,每个对象都有名称,城市和销售数量,如下表所示:

+----------+------------+-----------------+
| Name     | City       | Number of Sales |
+----------+------------+-----------------+
| Alice    | London     | 200             |
| Bob      | London     | 150             |
| Charles  | New York   | 160             |
| Dorothy  | Hong Kong  | 190             |
+----------+------------+-----------------+

分组

让我们开始使用命令式(Java-Lamba)按城市对员工进行分组:

Map<String, List<Employee>> result = new HashMap<>();
for (Employee e : employees) {
  String city = e.getCity();
  List<Employee> empsInCity = result.get(city);
  if (empsInCity == null) {
    empsInCity = new ArrayList<>();
    result.put(city, empsInCity);
  }
  empsInCity.add(e);
}

您可能熟悉这样的代码编写,并且您可以看到,完成如此简单的任务需要很多代码!

在Java 8中,您可以使用groupingBy收集器对单个语句执行相同的操作,如下所示:

Map<String, List<Employee>> employeesByCity =
  employees.stream().collect(groupingBy(Employee::getCity));

结果如下图:

{New York=[Charles], Hong Kong=[Dorothy], London=[Alice, Bob]}

通过将counting收集器传递给groupingBy收集器,还可以计算每个城市的雇员counting 。 第二收集器对分类到同一组的流中的所有元素执行进一步的还原操作。

Map<String, Long> numEmployeesByCity =
  employees.stream().collect(groupingBy(Employee::getCity, counting()));

结果如下图:

{New York=1, Hong Kong=1, London=2}

顺便说一句,这等效于以下SQL语句:

select city, count(*) from Employee group by city

另一个示例是计算每个城市的平均销售数量,可以使用averagingInt收集器结合groupingBy收集器来完成:

Map<String, Double> avgSalesByCity =
  employees.stream().collect(groupingBy(Employee::getCity,
                               averagingInt(Employee::getNumSales)));

结果如下图:

{New York=160.0, Hong Kong=190.0, London=175.0}

分区

分区是一种特殊的分组,其中的结果映射最多包含两个不同的组-一个用于true ,一个用于false 。 例如,如果您想找出最好的员工是谁,则可以使用partitioningBy收集器将他们分为销售额超过N的员工和销售额不超过N的员工:

Map<Boolean, List<Employee>> partitioned =
  employees.stream().collect(partitioningBy(e -> e.getNumSales() > 150));

这将产生以下结果:

{false=[Bob], true=[Alice, Charles, Dorothy]}

您还可以通过将groupingBy收集器传递给partitioningBy收集器来组合分区和分组。 例如,您可以计算每个分区内每个城市的雇员人数:

Map<Boolean, Map<String, Long>> result =
  employees.stream().collect(partitioningBy(e -> e.getNumSales() > 150,
                               groupingBy(Employee::getCity, counting())));

这将产生一个两层的Map:

{false={London=1}, true={New York=1, Hong Kong=1, London=1}}

翻译自: https://www.javacodegeeks.com/2015/11/java-8-streams-api-grouping-partitioning-stream.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值