要做到这一点,首先你必须按department分组,然后再按gender分组,而不是相反.
第一收集器groupingBy(Employee::getDepartment, _downstream_ )
将基于部门将数据集分成组.在应用它时,它将根据员工性别将映射到每个部门的数据划分为two个部分.最后,作为下游应用的Collectors.counting()
将为每department名员工提供gender名员工中的total number名.
因此,collect()
操作产生的中间体map将是Map<String, Map<Boolean, Long>>
-employee count×gender(Boolean
)型,每department(for simplicity, department is a plain string)个.
下一步是将这张 map 转换为Map<Employee.Gender, Map<String, Long>>
-employee count乘department,每个gender.
我的方法是在条目集上创建一个流,并将each entry替换为一个新的条目集,该条目集将gender作为其key,为了保留关于department的信息,其value将依次是一个条目,department作为键,count by department作为其值.
然后用entry key收集stream of entries和groupingBy
.将mapping
用作下游收集器,以提取nested entry.然后应用Collectors.toMap()
将Map.Entry<String, Long>
类型的条目收集到 map 中.
所有departments个都包含在sorted订单中
为了确保嵌套映射(department by count)中的顺序,应使用NavigableMap
.
为了做到这一点,需要使用预期为mapFactory
的toMap()
口味(it also expects a 102 which isn't really useful for this task since there will be no duplicates, but it has to be provided as well).
public static void main(String[] args) {
List<Employee> employeeRepository =
List.of(new Employee("IT", Employee.Gender.MALE),
new Employee("HR", Employee.Gender.MALE),
new Employee("MGMT", Employee.Gender.FEMALE));
Map<Employee.Gender, NavigableMap<String, Long>> departmentCountByGender = employeeRepository
.stream()
.collect(Collectors.groupingBy(Employee::getDepartment, // Map<String, Map<Boolean, Long>> - department to *employee count* by gender
Collectors.partitioningBy(employee -> employee.getGender() == Employee.Gender.MALE,
Collectors.counting())))
.entrySet().stream()
.flatMap(entryDep -> entryDep.getValue().entrySet().stream()
.map(entryGen -> Map.entry(entryGen.getKey() ? Employee.Gender.MALE : Employee.Gender.FEMALE,
Map.entry(entryDep.getKey(), entryGen.getValue()))))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> v1,
TreeMap::new))));
System.out.println(departmentCountByGender);
}
用于演示目的的Dummy Employee
class:
class Employee {
enum Gender {FEMALE, MALE};
private String department;
private Gender gender;
// etc.
// constructor, getters
}
Output
{FEMALE={HR=0, IT=0, MGMT=1}, MALE={HR=1, IT=1, MGMT=0}}