So, I have two collections, and I wish to combine both lists somehow.
Requirements are thusly:
- I have a collection newPersons
- I have a collection oldPersons
- I want a collection containing all the oldPersons but replaced (*some of) the oldPersons with the newPersons (based on id).
public record Person(Long id, String name, String surname) { }
Using the record class above.
Solution 1.
Create a new list based on oldPersons, replace items in this new list with equivalent items in newPersons.
This solution leaves much to be desired. It's confusing and error prone.
I was looking for something better.
public List<Person> mergeMetadata(List<Person> newPersons, List<Person> oldPersons) { var result = new ArrayList<>(oldPersons); newPersons.forEach(newPerson -> { result.stream() .filter(person -> person.id().equals(newPerson.id())) .findFirst() .ifPresent(result::remove); result.add(newPerson); }); return result; }
Solution 2.
Sometimes getting back to our roots using for-loops can help readability.
We could try it the other way around, see if that helps.
This time we create a new list based on newPersons and add an oldPerson if it's not already in the list.
This seems a little more clear.
public List<Person> mergeMetadata(List<Person> newPersons, List<Person> oldPersons) { var result = new ArrayList<>(newPersons); for (Person oldPerson : oldPersons) { if (result.stream().noneMatch(x -> x.id().equals(oldPerson.id()))) { result.add(oldPerson); } } return result; }
Solution 3.
Merge two collections into one list, by using a map.
public List<Person> mergeMetadata(List<Person> newPersons, List<Person> oldPersons) { Map<Long, Person> result = Stream .concat(newPersons.stream(), oldPersons.stream()) .collect(Collectors.toMap(Person::id, Function.identity(), (l, r) -> l)); return new ArrayList<>(result.values()); }
Although this solution seems to be the shortest (in code), using a Map function can be a bit daunting (it was for me) because of inherent complexity in the method call for creating it.
Still, perhaps it's just me and my inexperience with combining maps and streams.
I don't know if there's an even better way. Will keep an eye out.
No comments:
Post a Comment