I have a custom type which looks like this:
public class SampleObject {
private UUID id;
private List<ValueObject> values;
// getters, all-args constructor, etc.
}
The ValueObject just contains some Strings.
And I have a List of SampleObjects payload. Within that list, there are several objects with the same id but different values in the List<ValueObject>.
What I want to archive is to merge all objects with the same id and add all the different lists of the ValueObjects in one merged object.
At the end, I need again a list of SampleObjects.
What I tried is the following:
List<SampleObject> payload = // initializing the List
payload.stream().collect(Collectors.groupingBy(SampleObject::getId));
But this returns a Map of List of SampleObjects.
And I don't know how to merge then the objects under the value of this Map.
CodePudding user response:
Collectors.flatMapping()
In order to combine together and store into a single list all the ValueObjects that correspond to the same id you can use Collector flatMapping(), which expects a function that produces a Stream from the element (similarly to flatMap() operation) and a downstream Collector which tells how the new elements produced by the function need to be stored.
A combination of Collectors groupingBy() and flatMapping() would give you a map of type Map<UUID, List<ValueObject>>. To produce a List of SampleObjects out of it, you can create a stream map entries, transform each entry into a SampleObject and then collect the elements into a List.
That's how implementation might look like:
List<SampleObject> payload = // initializing the list
List<SampleObject> mergedData = payload.stream()
.collect(Collectors.groupingBy( // intermediate Map<UUID, List<ValueObject>>
SampleObject::getId,
Collectors.flatMapping(
sampleObject -> sampleObject.getValues().stream(),
Collectors.toList()
)
))
.entrySet().stream()
.map(entry -> new SampleObject(entry.getKey(), entry.getValue()))
.toList(); // for Java 16 or collect(Collectors.toList())
