I have to compare elements on two list (list1 to list2) and when the elements match with that of the code property, I have to replace with the value of tobereplace property.
In list1 I have
[{code:"1", name:"first name", tobereplace: ""} , {code:"2", name:"first name1", tobereplace: ""},
{code:"3", name:"first name2", tobereplace: ""}, {code:"4", name:"first name3", tobereplace: ""}]
in List2 I have:
[{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"}]
Ideally,List1 should have values of List2; How can we achieve this using Java8 streams
Supposing that the class is named Foo
and that the field to change is String valueToReplace
with getter/setter, you could use listOne.replaceAll()
in this way :
list1.replaceAll(one -> list2.stream()
.filter(other -> other.getCode().equals(one.getCode())
.findAny()
.map(Foo::getValueToReplace)
.ifPresent( newValue -> one.setValueToReplace(newValue));
return one;
)
The idea is for each elements of list1
you replace the valueToReplace
field of it by the value of the first match of list2
. Otherwise you do nothing.
This code is not as efficient as it could but for small lists it is perfect.
For bigger lists, using a Map
to store code/valueToReplace
is very welcome.
// 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;
)
Just keep the replace values in a map (with code as key) and then iterate over list1 to modify where necessary.
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
As josejuan points out in the comments, the Collectors.toMap
will throw an exception if list2 contains duplicate values. The OP doesn't really specify what to do in that case, but the solution is using a merge function in the Collectors.toMap
.
This will use the first element it encounters with any given code:
Map<String, String> replaceValues = list2.stream()
.collect(Collectors.toMap(x -> x.code, x -> x.tobereplace, (x1, x2) -> x1));
The merge policy could be anything, like using the first element with a non-empty value eg
If the list was known to not have duplicates, please use a Set instead of a List. It will make things clearer for anyone reading the code, and help you avoid unnecessary checks.
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.