字段上的Java8 Groupby并收集对象

时间:2018-08-03 08:39:56

标签: java group-by java-8 java-stream

假设我有以下列表:

List<Employee> employees = ....

其中

class Employee{
    private String employeeId;
    private String employeeName;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(employeeId, employee.employeeId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(employeeId);
    }
}

以下代码为我提供了每个员工姓名及其频率:

Map<String,Long> employeeNameWithFreq = employees
        .stream()
        .collect(Collectors.groupingBy(
                Employee::getEmployeeName,
                Collectors.counting()));

如何在字段groupBy的Java8流中employeeName,并在输出映射中获取对应的Employee对象作为键,并在其值中获取freq的值?我的意思是输出应为Map<Employee,Long>

注意equals()hashcode()方法已被字段employeeId覆盖,因此不能使用它们。基本上是在寻找一种比较字段可以作为参数传递的解决方案。

3 个答案:

答案 0 :(得分:2)

我不确定这是否是真正的目标,但是根据您的问题,您可能想将TreeMap与自定义Comparator一起使用,该自定义name只会比较某些选定字段中的Employee对象(例如此处TreeMap<Employee, Long> map = Stream. of( new Employee(1, "Adam"), new Employee(2, "Thomas"), new Employee(3, "Adam") ).collect(Collectors.groupingBy( Function.identity(), () -> new TreeMap<>(Comparator.comparing(Employee::getName)), Collectors.counting()) ); System.out.println(map.get(new Employee(33, "Adam"))); // Output: 2 // ID will be ignored by Comparator ---^^ )。

演示

var combinedReducers  = {
            Tasks: TaskDuck.reducer,
             Approval:()=> ({
                ApprovalDetail: ApprovalDuck.reducer,
                Decisions: DecisionsTasksDuck.reducer
            })
        };

        export const rootReducer = Redux.combineReducers<AppState>(combinedReducers);

答案 1 :(得分:0)

为什么不简单地第二次流过Employee

Map<String,Long> employeeNameWithFreq = employees
    .stream()
    .collect(
        Collectors.groupingBy(
            Employee::getEmployeeName,
            Collectors.counting()
        )
    );

Map<Employee, Long> employeeToNumColleaguesWithSameName = employees.stream()
    .collect(
        Collectors.toMap(
            Function.identity(),
            employee -> employeeNameWithFreq.get(employee.getEmployeeName())
        )
    );

答案 2 :(得分:-1)

您不能将Employee对象用作结果图的键,因为即使它们共享相同的名称,它们也具有不同的身份!如果您希望有一个包含特定名称出现次数的映射,则应该使用“名称”作为键,然后将“雇员列表”作为值,这样您就可以访问列表的大小以及每个共享此特定名称的员工的数量。

Map<String, List<Employee>> employeeIdWithFreq = employees
            .stream()
            .collect(Collectors
                .groupingBy(Employee::getEmployeeName, Collectors.toList()));

然后将名称(这些对象共享的唯一属性!)作为键,并将 employeeIdWithFreq.get(“ name”)。size() 发生次数。如果您对任何员工的存在感兴趣,可以通过 employeeIdWithFreq.get(employee.getName())

轻松访问

您可以实现您所要求的功能,但是这样,密钥可以是任何匹配的Employee对象。...

Map<Employee, Integer> employeeIdWithFreq = employees
        .stream()
        .collect(Collectors.groupingBy(Employee::getEmployeeName, Collectors.toList()))
        .values()
        .stream()
        .collect(Collectors.toMap(list-> list.stream().findAny(), List::size));