Starting point:
public class Employee {
private String id;
private String name;
private String age;
}
I have a list of Employee: List<Employee> employee;
Employee examples from the list:
{id="1", name="John", age=10}
{id="2", name="Ana", age=12}
{id="3", name="John", age=23}
{id="4", name="John", age=14}
Let's assume that age
is unique.
How can I remove all duplicates from the list based on the name
property and to keep in the output the entry with the largest age
?
The output should look like:
{id="2", name="Ana", age=12}
{id="3", name="John", age=23}
The way I tried:
HashSet<Object> temp = new HashSet<>();
employee.removeIf(e->!temp.add(e.getName()));
..but the this way the first match will be kept in employee
{id="1", name="John", age=10}
{id="2", name="Ana", age=12}
...and I have no idea how to put an another condition here to keep the one with the largest age
.
Here's a way that groups elements by name
and reduces groups by selecting the one with max 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());
Which returns [[id=2, name=Ana, age=12], [id=3, name=John, age=23]]
with your test data.
Apart from the accepted answer, here are two variants:
Collection<Employee> employeesWithMaxAge = employees.stream()
.collect(Collectors.toMap(
Employee::getName,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(Employee::getAge))))
.values();
This one uses Collectors.toMap
to group employees by name, letting Employee
instances as the values. If there are employees with the same name, the 3rd argument (which is a binary operator), selects the employee that has max age.
The other variant does the same, but doesn't use streams:
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));
Or, with 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))));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With