Complex aggregation using Java 8 streams

Given the class:

public class Item {
    private String field1;
    private String field2;
    private String field3;
    private Integer field4;

    // getters, constructor...
}

      

And one more group of classes (field1 and field2 store equivalent fields from the element):

public class Group {
    private String field1;
    private String field2;
}

      

I have List<Item>

one that I need to assemble into a map of the following structure:

Map<Group, Map<Field3, List<Field4>>>

      

Sample data:

Field1 | Field2 | Field3 | Field4
------ | ------ | ------ | ------
"f1"   | "f2"   | "a"    | 1
"f1"   | "f2"   | "a"    | 2
"f1"   | "f2"   | "a"    | 3
"f1"   | "f2"   | "b"    | 4
"f1"   | "f2"   | "b"    | 5
"f1"   | "f2"   | "c"    | 6
"f1a"  | "f2a"  | "a"    | 7
"f1a"  | "f2a"  | "a"    | 8

      

The expected output will look like this:

Group(field1=f1a, field2=f2a)={b=[7, 8]}, Group(field1=f1, field2=f2)={a=[1, 2, 3], b=[4, 5], c=[6]}

      

So far I have managed to aggregate over Field1, Field2 and Field3, so I have the following structure (where GroupEx

represents a POJO that contains fields 1, field 2 and field 3):

Map<GroupEx, List<Field4>>

      

The code for the aggregation is as follows:

Map<GroupEx, List<Integer>> aggregated = items.stream()
    .collect(Collectors.groupingBy(item -> new GroupEx(x.getField1(), x.getField2(), x.getField3())
           , Collectors.mapping(Item::getField4, Collectors.toList())));

      

I'm trying to get the syntax correct to allow me to group by Field1 and Field2, and then group Field3 and Field4 into a map as I need it.

Long arm syntax:

Map<Group<String, String>, Map<String, List<Integer>>> aggregated = new HashMap<>();
for (Item item : items) {
    Group key = new Group(item.getField1(), item.getField2());
    Map<String, List<Integer>> field3Map = aggregated.get(key);
    if (field3Map == null) {
        field3Map = new HashMap<>();
        aggregated.put(key, field3Map);
    }

    List<Integer> field4s = field3Map.get(item.getField3());
    if (field4s == null) {
        field4s = new ArrayList<>();
        field3Map.put(item.getField3(), field4s);
    }

    field4s.add(item.getField4());
}

      

Can anyone show me how my target group can be achieved?

+3


source to share


1 answer


Here the function is used



+7


source







All Articles