根据条件从List<Object>中删除重复项

8
起始点:
public class Employee {
    private String id;
    private String name;
    private String age;
}

我有一个员工列表:List<Employee> employee; 列表中的员工示例:
{id="1", name="John", age=10}
{id="2", name="Ana", age=12}
{id="3", name="John", age=23}
{id="4", name="John", age=14}

假设age是唯一的。
基于name属性,如何从列表中删除所有重复项并保留具有最大age的条目到输出中?
输出应该如下所示:
{id="2", name="Ana", age=12}
{id="3", name="John", age=23}

我尝试的方式是:
HashSet<Object> temp = new HashSet<>();
employee.removeIf(e->!temp.add(e.getName()));

但是这样第一个匹配项将会被保留在employee中。
{id="1", name="John", age=10}
{id="2", name="Ana", age=12}

"...我不知道如何在这里添加另一个条件来保留年龄最大的那个。"

HashSet<Object>?你的员工对象是否可比较?只需确保equals将具有相同名称的对象报告为相等。 - Naman
1
你应该先对员工列表进行排序。 - Cherokee
4个回答

10

这里有一个按照name分组并通过选择最大age的方式来缩小组的方法:

List<Employee> uniqueEmployees = employees.stream()
            .collect(Collectors.groupingBy(Employee::getName,
                    Collectors.maxBy(Comparator.comparing(Employee::getAge))))
        .values()
        .stream()
        .map(Optional::get)
        .collect(Collectors.toList());

使用您的测试数据,将返回[[id=2, name=Ana, age=12], [id=3, name=John, age=23]]


1
谢谢,这是非常优雅的解决方案。 - Sviatlana

5
除了被接受的答案,这里还有两个变种方案:
Collection<Employee> employeesWithMaxAge = employees.stream()
    .collect(Collectors.toMap(
             Employee::getName,
             Function.identity(),
             BinaryOperator.maxBy(Comparator.comparing(Employee::getAge))))
    .values();

这个示例使用Collectors.toMap按名称对员工进行分组,让Employee实例作为值。如果有相同名称的员工,则第三个参数(二元运算符)选择年龄最大的员工。
另一个变体执行相同的操作,但不使用流:
Map<String, Employee> map = new LinkedHashMap<>(); // preserves insertion order
employees.forEach(e -> map.merge(
        e.getName(), 
        e, 
        (e1, e2) -> e1.getAge() > e2.getAge() ? e1 : e2));

或者,使用 BinaryOperator.maxBy:
Map<String, Employee> map = new LinkedHashMap<>(); // preserves insertion order
employees.forEach(e -> map.merge(
        e.getName(), 
        e, 
        BinaryOperator.maxBy(Comparator.comparing(Employee::getAge))));

1

ernest_k的回答很好,但如果您想避免添加重复项,可以使用以下方法:

public void addToEmployees(Employee e) {
    Optional<Employee> alreadyAdded = employees.stream().filter(employee -> employee.getName().equals(e.getName())).findFirst();
    if(alreadyAdded.isPresent()) {
        updateAgeIfNeeded(alreadyAdded.get(), e);
    }else {
        employees.add(e);
    }
}

public void updateAgeIfNeeded(Employee alreadyAdded, Employee newlyRequested) {
    if(Integer.valueOf(newlyRequested.getAge()) > Integer.valueOf(alreadyAdded.getAge())) {
        alreadyAdded.setAge(newlyRequested.getAge());
    }
}

只需使用addToEmployees方法将Employee添加到列表中。

您还可以创建继承ArrayList的类,并重写add方法,然后使用自己的列表 :)


0

如果年龄大于等于Map<String, Employee>(其中string是姓名)中的年龄,则可以将值添加到其中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接