我必须比较两个列表(list1到list2)上的元素,并且当这些元素与code属性的元素匹配时, 我必须替换为tobereplace属性的值。
我在list1中有
#define R "x"
const char* s = R"y"; // ill-formed raw string, not "x" "y"
在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: ""}]
理想情况下,List1应该具有List2的值; 我们如何使用Java8流实现这一目标
答案 0 :(得分:1)
假设该类名为Foo
,并且要使用getter / setter更改的字段为String valueToReplace
,则可以通过以下方式使用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;
)
答案 1 :(得分:1)
只需将替换值保存在一个映射中(以代码作为键),然后遍历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));
编辑
正如josejuan在评论中指出的,如果list2包含重复值,则Collectors.toMap
将引发异常。在这种情况下,OP并未真正指定要执行的操作,但解决方案是在Collectors.toMap
中使用合并功能。
这将使用任何给定代码遇到的第一个元素:
Map<String, String> replaceValues = list2.stream()
.collect(Collectors.toMap(x -> x.code, x -> x.tobereplace, (x1, x2) -> x1));
合并策略可以是任何内容,例如将第一个元素与非空值一起使用
如果已知列表没有重复项,请使用Set而不是List。对于任何阅读该代码的人,它都将使事情变得更加清楚,并帮助您避免不必要的检查。