I have List<Object[]>
inner join MySQL query, I need to create a map key id and value object.
The Code below works, but how to do it best with Streams?
Map<Object, List<Object[]>> convert(List<Object[]> objects) {
Map<Object, List<Object[]>> objectListMap = objects.stream()
.collect(Collectors.toMap(obj -> obj[0], obj -> {
List<Object[]> list = new ArrayList<>();
list.add(obj);
return list;
}, (obj1, obj2) -> {
obj1.addAll(obj2);
return obj1;
}));
return objectListMap;
}
Object[] objects structure:
objects[0] = person id
...
objects[10] = event id
...
objects[15] = event name
This query found all the person with the event visited, but the index in the objects array from 0 to 10 may be the same, 11-15 always change.
And I want to merge all object-lists that have the same id (objects[0]).
next for each value in Map> convert to POJO:
PersonWithEvent converToEntity(List<Object[]> objects) {
Optional< PersonWithEvent > personWithEvent =
objects.stream()
.findFirst().map(obj -> {
PersonWithEvent p = new PersonWithEvent();
p.setId((Integer) obj[0]);
...
return p;
});
personWithEvent.ifPresent(p -> {
List<PersonEvent> personEvents = objects.stream()
.map(obj -> {
PersonEvent pe = new PersonEvent();
pe.setName((String) obj[2]);
...
return pe;
})
.collect(Collectors.toList());
p.setPersonEvents(personEvents);
});
return personWithEvent.get();
And Is it possible to do it for one stream?
2 Answers 2
It seems you need to group by element at index zero of an array Object
Collectors.groupingBy
groups by the key
Map<Object, List<Object[]>> map = objects.stream()
.collect(Collectors.groupingBy(o -> o[0]));
with null and empty checks
Map<Object, List<Object[]>> map = objects.stream()
.filter(o -> o != null && o.length != 0)
.collect(Collectors.groupingBy(o -> o[0]));
Example
List<Object[]> objects = new ArrayList<>();
objects.add(new Object[] { 0, 1, 2, 3, 4, 5 });
objects.add(new Object[] { 1, 1, 2, 3, 4, 5 });
objects.add(new Object[] { 2, 1, 2, 3, 4, 5 });
objects.add(new Object[] { 0, 6, 7, 8, 9 });
Map<Object, List<Object[]>> map = objects.stream()
.collect(Collectors.groupingBy(o -> o[0]));
System.out.println(map);
output is like
{
0 = [[Ljava.lang.Object;@378bf509,
[Ljava.lang.Object;@5fd0d5ae],
1 = [[Ljava.lang.Object;@2d98a335],
2 = [[Ljava.lang.Object;@16b98e56]
}
you can see 0
has two List<Object[]>
values grouped by
4 Comments
Collectors#groupingBy
is actually a nice and clean approach. Never worked with it before but it seems worth to learn..filter(Objects::nonNull)
for removing null
values. Just in case you didn't know that method.I would make the whole procedure more explicit and clean. Using a mixed-style with lots of comments and good variable names.
This should help a lot when it comes down to reading, understanding and maintaining your code.
Map<Object, List<Object[]>> convert(List<Object[]> entities) {
Map<Object, List<Object[]>> idToEntitesWithSameId = new HashMap<>();
entities.forEach(entity -> {
// Create an entry for each entity,
// merge with entities of same id
Object id = entity[0];
// Get current value or empty list
List<Object[]> entitiesWithId = idToEntitesWithSameId
.computeIfAbsent(id, ArrayList::new);
// Add own entity, merge with other
// entities of same id
Arrays.stream(entity).forEach(entitiesWithId::add);
});
return idToEntitesWithSameId;
}
List<Object[]>
? What are the keys and what the values for the map? What is themerge
function supposed to do?Object[]
array has an id at index0
and you want to map this id to the rest whole array likeobjects[0] => objects
. And additionally you want to merge all object-lists that have the same id (objects[0]
).