Update one list based on another list using stream
Update one list based on another list using stream
I'd like to update items in an existing list from an incoming list.
class Person
String id;
String name;
String age;
.
.
.
@Override
public boolean equals(Object object)
return ... ((Person) object).id.equals(this.id);
The current list is shorter:
ArrayList<Person> currentList = Arrays.asList(
new Person("0", "A", 25),
new Person("1", "B", 35)
);
The received list is bigger, e.g.
ArrayList<Person> updatedList = Arrays.asList(
new Person("0", "X", 99),
new Person("1", "Y", 100),
new Person("2", "C", 2),
new Person("3", "D", 3),
new Person("4", "E", 5)
);
including the items(identified by their id) from current list.
I'd like to replace all the items in the current list, with the same one's from new list.
So after transformation, current list will be
Person(0, "X", 99), Person(1, "Y", 100)
Is it possible to do with Stream only.
Map
Does person class has only three fields? do you want to update only two fields(name and age) from the other list?
– pvpkiran
Aug 27 at 12:08
@pvpkiran hi, it may have more fields. Since any field maybe updated, I'd like to replace the objects from the new list directly to the old list.
– Abu Ruqaiyah
Aug 27 at 12:10
There are many details missing. what if some id's are not present in the updatedList? And how big a list are we talking about?
– pvpkiran
Aug 27 at 12:11
What do you mean by "operators" and Is there a reason you want to use streams? Using
Collection methods removeAll, retainAll, and addAll. might be enough and might help readability. For small lists the performance would not be different, I think.– Malte Hartwig
Aug 27 at 13:52
Collection
removeAll
retainAll
addAll
4 Answers
4
This will achieve what you are asking.
Map<String, Person> collect = updatedList
.stream()
.collect(Collectors.toMap(Person::getId, Function.identity()));
currentList = currentList
.stream()
.map(Person::getId)
.map(collect::get)
.collect(Collectors.toList());
As @Holger mentioned, doing this for a small List is not so elegant
If the currentList is always a subset of the updatedList - means that all the currentList will appear in the updatedList, you can do the following:
currentList
updatedList
currentList
updatedList
Set<String> setOfId = currentList.stream()
.map(person -> person.getId()) // exctract the IDs only
.collect(Collectors.toSet()); // to Set, since they are unique
List<Person> newList = updatedList.stream() // filter out those who don't match
.filter(person -> setOfId.contains(person.getId()))
.collect(Collectors.toList());
If the updatedList and currentList differ significantly - both can have unique persons, you have to do the double iteration and use Stream::map to replace the Person. If not found, replace with self:
updatedList
currentList
Stream::map
Person
List<Person> newList = currentList.stream()
.map(person -> updatedList.stream() // map Person to
.filter(i -> i.getId().equals(person.getId())) // .. the found Id
.findFirst().orElse(person)) // .. or else to self
.collect(Collectors.toList()); // result to List
Assuming that you want the currentList item to be replaced by the object from the updatedList the following should work:
currentList.stream().map((p) ->
return updatedList.stream().filter(u -> p.equals(u)).findFirst().orElse(p);
).collect(Collectors.toList());
Yes it is possible using stream,
filter record having ids in first list
List<String> ids = currentList.stream().map(Person::getId).collect(Collectors.toList());
currentList = updatedList.stream().filter(o -> ids.contains(o.getId()))
.collect(Collectors.toList());
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I doubt that you can find a solution that is more elegant than two nested loop. For larger lists, converting one list to a
Mapand doing only one loop has a point, but for such short lists, it won’t pay off.– Holger
Aug 27 at 12:07