Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group a list inside an object by multiple attributes : Java 8

How do I group a list inside an object by two of the object attributes?

I'm using Drools 7.9.0 and Java 8. I have a Result class that is used as return to each matched Drools rule.

import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Data
@NoArgsConstructor
public class Result implements Serializable {

    private Integer id;
    private String name;
    private List<Occurrences> occurrences = new ArrayList<>();

    public void addOccurrence(Occurrences occurrence) {
        this.occurrences.add(occurrence);
    }
}

After Drools execution, I end up with a List<Result>. Converted to JSON it looks like this.

CURRENT OUTCOME:

[
     {
        name: "Whatever"
        id: 0001,
        occurrences: [{
           (...)
        }]
    },
    {
        name: "Whatever"
        id: 0001,
        occurrences: [{
           (...)
        }]
    },
    {
        name: "Whatever"
        id: 0002,
        occurrences: [{
           (...)
        }]
    },
    {
        name: "Other thing"
        id: 0002,
        occurrences: [{
           (...)
        }]
    }
]

I need to group up my list of Results so the ocurrences are grouped by id and name, like this.

EXPECTED OUTCOME:

[
    {
        name: "Whatever"
        id: 0001,
        occurrences: [{
           (...)
        }, {
           (...)
        }]
    },
    {
        name: "Whatever"
        id: 0002,
        occurrences: [{
           (...)
        }]
    },
    {
        name: "Other thing"
        id: 0002,
        occurrences: [{
           (...)
        }]
    }
]

What would be the best way to implement this? I have two options:

  1. Change Drools rules so my List<Result> is already structured the way I need. Maybe create a class with a addResult method that checks the list for id and name and add the occurrence to the right entry. But this is not ideal, because it will increase complexity inside the rules.
  2. Post-process my List<Result> so it groups the occurrences by id and name. But I have no idea how to do this in an optimized and simple way.

What's the best way to do the 2nd option?

like image 416
Lauro Gripa Neto Avatar asked Jan 01 '23 08:01

Lauro Gripa Neto


1 Answers

You may do it like so,

Map<String, List<Result>> resultsWithSameIdAndName = results.stream()
    .collect(Collectors.groupingBy(r -> r.getId() + ":" + r.getName()));

List<Result> mergedResults = resultsWithSameIdAndName.entrySet().stream()
    .map(e -> new Result(Integer.valueOf(e.getKey().split(":")[0]), 
        e.getKey().split(":")[1],
        e.getValue().stream().flatMap(r -> r.getOccurrences().stream())
            .collect(Collectors.toList())))
        .collect(Collectors.toList());
like image 76
Ravindra Ranwala Avatar answered Jan 04 '23 15:01

Ravindra Ranwala