Как установить значение для поля одного списка объектов из другого списка объектов, имеющих общее поле? - PullRequest
1 голос
/ 15 января 2020

У меня есть 2 списка, скажем,

1 -> List<Employee> list1;
2 -> List<Age> list2

class Employee {
    String name;
    String age;
    String address;
}

class Age {
    String name;
    String age;
}

Что мне нравится делать, так это то, что мне нужно заменить возраст для всех записей в Список сотрудников на возраст в Возрастной список с одинаковым именем в обоих. Как я мог добиться этого в Java 8?

Ответы [ 4 ]

6 голосов
/ 15 января 2020

Вы можете передавать List<Age> внутри итерации элементов List<Employee>:

list1.forEach(e -> e.setAge(
     list2.stream()                                     // Stream<Age>
          .filter(a -> a.getName().equals(e.getName())) // ... find the name match
          .map(Age::getAge)                             // ... extract the age
          .findAny().orElse("unknown")));               // ... return it or else "unknown"
  • Если совпадений имен не найдено, значение по умолчанию устанавливается на unknown.
  • Кроме того, вы должны убедиться, что нет дублирующихся имен, на которых основан возраст.
  • Возраст String - это нормально?
  • Вы Вы уверены, что нет значений null?

Если вы хотите удалить такие несопоставленные записи, я предлагаю вам использовать Iterator с Map<String, List<Age>>:

Map<String, List<Age>> map = list2.stream()
    .collect(Collectors.groupingBy(             // Map<String, List<Age>>
         Age::getName));                        // ... where 'name' is the key

final  Iterator<Employee> iterator = list1.iterator();
while (iterator.hasNext()) {                    // Iterating List<Employee>
    final Employee e = iterator.next();         // Employee
    if (map.containsKey(e.getName())) {         // If there is Age with equal 'name'
        final String age = map.get(e.getName()) // ... get the first found age
            .get(0).getAge();
        e.setAge(age);                          // ... set it to the Employee
    } else iterator.remove();                   // ... or else remove the Employee
}

Опять заботимся о пунктах, которые я перечислил выше. Более того, если вы не хотите использовать первый найденный возраст map.get(e.getName()).get(0).getAge(), вам нужно выполнить Stream::reduce над Stream<Age>, например:

// null doesn't occurunless the Age::getAge returns null
// The reducing would be much easier if the age is int
// Feel free to find max/min of the ages... up to you
String age = map.get(e.getName()).stream().map(Age::getAge).reduce(...).orElse(null); 

Вывод: - это неуклюжий путь, и я лично придерживаюсь процедурного подхода -1036 *.

4 голосов
/ 15 января 2020

Это будет работать, только если name уникально.

Начните с создания карты от имени к возрасту:

Map<String,String> nameToAge = list2.stream().collect(Collectors.toMap(Item::getName, Item::getAge));

Теперь используйте nameToAge в ваших поисках:

List<String> names = list1.stream()
    .map(e -> new Employee(e.getName(), nameToAge.get(e.getName()), e.getAddress()))
    .collect(Collectors.toList());

Приведенный выше код предполагает, что ваши классы правильно инкапсулировали свои свойства и что класс Employee имеет соответствующий конструктор.

2 голосов
/ 15 января 2020

Вместо использования list2 для поиска вы должны создать HashMap. Потому что ArrayList имеет производительность O (n) для поиска возраста по имени из list2, в то время как HashMap Map<String, String> ageWithName имеет производительность O (1) для поиска в среднем.

Function<Employee, String> findAge принимает сотрудника в качестве входных данных и дает вам возраст:

Map<String, String> ageWithName = list2.stream().collect(Collectors.toMap(Age::getName, Age::getAge));
Function<Employee, String> findAge = e -> ageWithName.get(e.getName());

list1.stream().forEach(e -> e.setAge(findAge.apply(e)));
1 голос
/ 15 января 2020

Прямой подход будет

for (int i = 0; i < list1.size(); i++) {
    Employee employee = list1.get(i);
    for (int j = 0; j < list2.size(); j++) {
       Age age = list2.get(j);
       if (employee.name.equals(age.name)) {
           employee.age = age.age;
           list1.set(i, employee);
       }
    }
}

Вы также можете реализовать метод equals в employee и использовать список # indexOf

for (int i = 0; i < list1.size(); i++) {
    Employee employee = list1.get(i);
    int ageIndex = list2.indexOf(employee); //or list2.indexOf(employee.name);
    if (ageIndex != -1) {
       employee.age = list2.get(ageIndex).age;
       list1.set(i, employee);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...