Issue
I have a List<Object[]>
where the Object[]
has the size of 3
and comes from a query. The result of the query is as follows:
| vehicleId | modelId | serviceId |
|------------------------------------|---------|-----------------|
|93bf3e92-7a37-4e23-836d-eed5a104341f| 214|80a7-ce5640b18879|
|b4066520-e127-44b7-bcc0-1d1187de559c| 214|80a7-ce5640b18879|
|ae6cb0fe-1501-4311-a2b4-cfb8b4f51ca4| 214|80a7-ce5640b18879|
|cf80ff11-6e23-4c19-8b6d-55d34d131566| 214|80a7-ce5640b18879|
It should be mapped in the List below. The second and last columns will be mapped to modelId and serviceId whilst the first column should become a list of vehicleIds.
I need to map it into a List<MyDTO>
where MyDTO
is as follows:
MyDTO{
// constructor
MyDTO(String modelId, String serviceId, List<String> vehicleIds){...}
String modelId;
String serviceId;
List<String> vehicleIds;
}
I am trying to figure out how to group by in a stream but nothing seems to come out. That's where I'm blocked...
listOfObjectArrays.stream()
.map(objects -> new MyDTO((String) objects[0], (String) objects[1], null));
Can't figure out how to apply a reduce operation that does the job, any help really appreciated!
Edit: Sorry I forgot to mention that I'm stuck with Java 8. Thank you all for the great answers.
Solution
You can create a nested intermediate map by grouping your data by modelId
and then serviceId
using groupingBy()
and mapping()
collectors.
And then create a stream over entry set. And flatten each inner map creating new MyDTO
based on every combination of modelId
and serviceId
.
Map<String, Map<String, List<String>>> vehicleIdByModelIdAndServiceId =
listOfObjectArrays.stream()
.collect(Collectors.groupingBy(objects -> (String) objects[1],
Collectors.groupingBy(objects -> (String) objects[2],
Collectors.mapping(objects -> (String) objects[0],
Collectors.toList()))));
List<MyDTO> result = vehicleIdByModelIdAndServiceId.entrySet().stream()
.flatMap(baseEntry -> baseEntry.getValue().entrySet().stream()
.map(entry -> new MyDTO(baseEntry.getKey(), entry.getKey(), entry.getValue())))
.collect(Collectors.toList());
Another option is to use a Map.Entry
as a key in the intermediate map, and a value will be a list of vehicleId
.
List<MyDTO> result = listOfObjectArrays.stream()
.collect(Collectors.groupingBy(objects -> new AbstractMap.SimpleEntry<>((String) objects[1], (String) objects[2]),
Collectors.mapping(objects -> (String) objects[0],
Collectors.toList())))
.entrySet().stream()
.map(entry -> new MyDTO(entry.getKey().getKey(),
entry.getKey().getValue(),
entry.getValue()))
.collect(Collectors.toList());
Answered By - Alexander Ivanchenko
Answer Checked By - Gilberto Lyons (JavaFixing Admin)