Java 8 сравнить 2 списков на основе собственности - PullRequest
0 голосов
/ 21 июня 2019

Мне нужно сравнить элементы в двух списках (от list1 до list2), и когда элементы соответствуют элементу свойства code, я должен заменить его значением свойства tobereplace.

В list1 у меня есть

[{code:"1", name:"first name", tobereplace: ""} , {code:"2", name:"first name1", tobereplace: ""}, 
{code:"3", name:"first name2", tobereplace: ""}, {code:"4", name:"first name3", tobereplace: ""}]

в List2 У меня есть:

[{code:"1", name:"first name", tobereplace: ""} , {code:"2", name:"first name1", tobereplace: "" }, 
{code:"3", name:"first name2", tobereplace: ""}, {code:"4", name:"first name3", tobereplace: "this should come in list1"}]

В идеале, List1 должен иметь значения List2;Как мы можем достичь этого, используя потоки Java8

Ответы [ 2 ]

1 голос
/ 22 июня 2019

Просто сохраните значения замены на карте (с кодом в качестве ключа), а затем переберите list1, чтобы изменить его, где это необходимо.

Map<String, String> replaceValues = list2.stream()
    .collect(Collectors.toMap(x -> x.code, x -> x.tobereplace));
list1.stream
    .filter(x -> replaceValues.containsKey(x.code))
    .forEach(x -> x.tobereplace = replaceValues.get(x.code));

EDIT

Как указывает Жозеюан в комментариях, Collectors.toMap сгенерирует исключение, если list2 содержит повторяющиеся значения. ОП на самом деле не указывает, что делать в этом случае, но решение использует функцию слияния в Collectors.toMap.

Это будет использовать первый элемент, с которым он сталкивается с любым данным кодом:

Map<String, String> replaceValues = list2.stream()
    .collect(Collectors.toMap(x -> x.code, x -> x.tobereplace, (x1, x2) -> x1));

Политика слияния может быть любой, например, использовать первый элемент с непустым значением, например,

Если известно, что в списке нет дубликатов, используйте набор вместо списка. Это прояснит ситуацию для каждого, кто читает код, и поможет избежать ненужных проверок.

1 голос
/ 22 июня 2019

Предположим, что класс назван Foo, а поле, которое нужно изменить, равно String valueToReplace с getter / setter, вы можете использовать listOne.replaceAll() следующим образом:

list1.replaceAll(one ->  list2.stream()
                              .filter(other -> other.getCode().equals(one.getCode())
                              .findAny()
                              .map(Foo::getValueToReplace)
                              .ifPresent( newValue -> one.setValueToReplace(newValue));
                        return one;
                )

Идея состоит в том, что для каждого элемента list1 вы заменяете его поле valueToReplace значением первого совпадения list2. В противном случае вы ничего не делаете.
Этот код не так эффективен, как мог бы, но для небольших списков он идеален.
Для больших списков использование Map для хранения code/valueToReplace очень приветствуется.

// supposing that the code are unique in each list
Map<Integer, String>  mapOfValueToReplaceByCode =
    list2.stream()
         .collect(toMap(Foo::getCode, Foo::getValueToReplace));

list1.replaceAll(one -> {
                 String newValue = mapOfValueToReplaceByCode.get(one.getCode());
                 if (newValue != null){ 
                     one.setValueToReplace(newValue);
                 }
                  return one;
                )
...