Удалить дубликаты из списка <Object>в зависимости от условия - PullRequest
0 голосов
/ 19 октября 2018

Начальная точка:

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}

... и я понятия не имею, как поставить еще одно условие, чтобы сохранить с наибольшим age.

Ответы [ 4 ]

0 голосов
/ 19 октября 2018

Помимо принятого ответа , здесь есть два варианта:

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))));
0 голосов
/ 19 октября 2018

Этот способ группирует элементы по name и сокращает группы, выбирая элемент с 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());

, который возвращает [[id=2, name=Ana, age=12], [id=3, name=John, age=23]] с вашими тестовыми данными.

0 голосов
/ 19 октября 2018

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 голосов
/ 19 октября 2018

Вы можете добавлять значения в Map<String, Employee> (где строка - имя), только если возраст больше, чем тот, что на карте.

...