Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group object by field and nested object's fields with Java streams

What I would like to do is group elements of a List in order to create a map, based on specific fields. The desired output is the following: Map<String,Map<String,Map<String,MasterObject>>>. The order of the keys is date, type, color.

My code is as follows

public class MasterObject{
   private String date;
   private List<SubObject> subObject;
}

public class SubObject{
   private String type;
   private String color;
}

What I have tried and used is Collectors.groupingBy which works great if your fields are members of the same Object (ex. date), but haven't managed to make it work for containing objects (ex. subObject). My input is a List<MasterObject>. It could be done the hard way by using Map's put and get but maybe there is a much cleaner way to make it work with Java streams.

What I have tried thus far is the following:

    Map<String, Map<List<String>, List<MasterObject>>> collect = faList.stream().collect(
    Collectors.groupingBy(f -> f.getDate(),
    Collectors.groupingBy(f -> f.getSubObject().stream().map(z -> z.getType()).collect(Collectors.toList()))));

In my sample above, I haven't managed to achieve to group elements by type, instead my key is a List<String>.Also my list should have a group by color as well.

like image 724
Jacob Avatar asked Jan 29 '26 09:01

Jacob


1 Answers

I would use a custom object to keep flattened values:

public class CustomObject {
    private String date;
    private String type;
    private String color;
    private MasterObject masterObj;
    
    // constructor, getters, setters
}

Try this:

SubObject sub1 = new SubObject("typeA", "red");
SubObject sub2 = new SubObject("typeA", "blue");
SubObject sub3 = new SubObject("typeB", "green");
SubObject sub4 = new SubObject("typeB", "green");
SubObject sub5 = new SubObject("typeC", "red");
SubObject sub6 = new SubObject("typeC", "blue");

List<MasterObject> masterObjList = new ArrayList<>();

masterObjList.add(new MasterObject("01/01/2020", Arrays.asList(sub1, sub2, sub3)));
masterObjList.add(new MasterObject("02/01/2020", Arrays.asList(sub4, sub5, sub6)));

Map<String, Map<String, Map<String, MasterObject>>> result = masterObjList.stream().flatMap(
        o -> o.getSubObject().stream().map(s -> new CustomObject(o.getDate(), s.getType(), s.getColor(), o)))
        .collect(Collectors.groupingBy(CustomObject::getDate, Collectors.groupingBy(CustomObject::getType,
                Collectors.toMap(CustomObject::getColor, CustomObject::getMasterObj))));

result.entrySet().forEach(e -> {
    System.out.println(e.getKey());
    e.getValue().entrySet().forEach(e1 -> {
        System.out.println("\t" + e1.getKey());
        e1.getValue().entrySet().forEach(e2 -> {
            System.out.println("\t\t" + e2.getKey());
        });
    });
});

Output:

01/01/2020
    typeB
        green
    typeA
        red
        blue
02/01/2020
    typeC
        red
        blue
    typeB
        green
like image 55
Hülya Avatar answered Jan 31 '26 21:01

Hülya



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!