'Grouping a list of flat objects in a nested structure

I have a List of objects A, where the object A has this form:

Class A {
private String a1;
private String a2;
private String a3;
private String a4;
private String a5;
private String a6;
}

I need to group this List first by a1 and then by a3, resulting in this way: Map<B, Map<C, List<D>>>, where the object B has this form

Class B {
private String a1; 
private String a2;
}

and where the object C has this form

Class C {
private String a3;
private String a4;
}

and where the object D has this form

Class D {
private String a5;
private String a6;
}

Is this possibile with streams in Java 11? Any other ways to achieve this goal are welcome, thanks very much!



Solution 1:[1]

Suppose you have these lombok annotations on your classes (It's fine if you don't have lombok - you can just add these boilerplate to your classes if you don't have them already):

@Getter
class A {
    private String a1;
    private String a2;
    private String a3;
    private String a4;
    private String a5;
    private String a6;
}

@AllArgsConstructor
@EqualsAndHashCode(exclude = "a2")
class B {
    private String a1;
    private String a2;
}

@AllArgsConstructor
@EqualsAndHashCode(exclude = "a4")
class C {
    private String a3;
    private String a4;
}

@AllArgsConstructor
class D {
    private String a5;
    private String a6;
}

Note that it is important that B and C's equals and hashCode only depend on a1 and a3 respectively.

Then given List<A> aList, you can nest the groupingBy collectors like this, and at the very end, map each thing to a D.

var map = aList.stream().collect(
    Collectors.groupingBy(
        x -> new B(x.getA1(), x.getA2()),
        Collectors.groupingBy(
            x -> new C(x.getA3(), x.getA4()),
            Collectors.mapping(
                x -> new D(x.getA5(), x.getA6()),
                Collectors.toList()
            )
        )
    )
);

and map will be a Map<B, Map<C, List<D>>>.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sweeper