如何在应用嵌套分组时保留所有子组通过收集器
我正在尝试按性别和部门对员工列表进行分组。
如何确保所有部门都包含在每个性别的排序顺序中,即使相关性别计数为零嗯>?
目前,我有以下代码和输出
employeeRepository.findAll().stream()
.collect(Collectors.groupingBy(Employee::getGender,
Collectors.groupingBy(Employee::getDepartment,
Collectors.counting())));
//output
//{MALE={HR=1, IT=1}, FEMALE={MGMT=1}}
首选输出是:
{MALE={HR=1, IT=1, MGMT=0}, FEMALE={HR=0, IT=0, MGMT=1}}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为此,首先必须按部门分组,然后才按性别分组,而不是相反。
第一个收集器
groupingBy(Employee::getDepartment, _downstream_ )
将根据部门将数据集拆分为组。由于下游收集器partitioningBy(employee -> employee.getGender() == Employee.Gender.MALE, _downstream_ )
将被应用,它将映射到每个部门的数据划分为 根据员工性别分为两部分。最后,作为下游应用的Collectors.counting()
将提供每个部门<的每个性别员工的总数 /强>。因此,由
collect()
操作生成的中间 map 类型将为Map>
- < em>每个部门按性别划分的员工人数(布尔值
)(为了简单起见,部门是一个纯字符串< /em>)。下一步将此映射转换为
Map>
- 每个部门的员工人数 性别。我的方法是在条目集上创建一个流,并将每个条目替换为一个新条目,该新条目将性别作为其键,并且为了保留有关部门的信息,其值依次将是一个以部门为键和一个带有部门的条目>按部门计算作为其值。
然后通过条目键使用
groupingBy
收集条目流。应用映射
作为下游收集器来提取嵌套条目。然后应用Collectors.toMap()
将Map.Entry
类型的条目收集到地图中。为了确保嵌套地图中的顺序(按计数划分)
NavigableMap
应该使用。为此,需要使用需要
mapFactory
的toMap()
风格(它还需要一个mergeFunction
这对于此任务来说并不是真正有用,因为不会有重复项,但也必须提供它)。用于演示目的的虚拟
Employee
class:输出
To achieve that, first you have to group by department, and only then by gender, not the opposite.
The first collector
groupingBy(Employee::getDepartment, _downstream_ )
will split the data set into groups based on department. As it downstream collectorpartitioningBy(employee -> employee.getGender() == Employee.Gender.MALE, _downstream_ )
will be applied, it'll divide the data mapped to each department into two parts based on the employee gender. And finally,Collectors.counting()
applied as a downstream will provide the total number of employees of each gender for every department.So the intermediate map produced by the
collect()
operation will be of typeMap<String, Map<Boolean, Long>>
- employee count by gender (Boolean
) for each department (for simplicity, department is a plain string).The next step in transform this map into
Map<Employee.Gender, Map<String, Long>>
- employee count by department for each gender.My approach is to create a stream over the entry set and replace each entry with a new one, which will hold a gender as its key and in order to preserve the information about a department its value in turn will be an entry with a department as a key and a with a count by department as its value.
Then collect the stream of entries with
groupingBy
by the entry key. Applymapping
as a downstream collector to extract the nested entry. And then applyCollectors.toMap()
to collect entries of typeMap.Entry<String, Long>
into map.To insure the order in the nested map (department by count) a
NavigableMap
should be used.In order to do that, a flavor of
toMap()
that expects amapFactory
needs to be used (it also expects amergeFunction
which isn't really useful for this task since there will be no duplicates, but it has to be provided as well).Dummy
Employee
class used for demo-purposes:Output
您可以继续处理代码的结果:
如果您想用一行代码获得结果,则代码的可读性或可维护性可能不会很好。
但是,如果您不介意使用第三方库,还有一种选择: abacus-common
声明:我是 abacus-common 的开发者
You can continue to work on the result of your code:
Probably readability or maintainability of code won't be good if you want to achieve result with one line of code.
However, there is one alternative if you don't mind to use third-party library: abacus-common
Declaration: I'm the developer of abacus-common