java stream List<Object[]> to Map<Object, List<Object[]>>

Viewed 5861

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

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

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;
}
Related