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))));
ernest_k answer is great but if you maybe want to avoid adding duplicates you can use this:
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());
}
}
Just use addToEmployees
method to add Employee
to your list.
You can also create class extending ArrayList
and override add
method like so and then use your own list :)
只有当age大于等于地图中的年龄时Map<String, Employee>
才能在Map<String, Employee>
(其中string是name)中添加值。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.