Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Java 8 Collectors groupingBy to get a Map with a Map of the collection?

Imagine these classes

class Subject {
   private int id;
   private Type type;
   private String origin;
   private String name;

   Subject(int id, Type type, String origin, String name) {
      this.id = id;
      this.type = type;
      this.origin = origin;
      this.name = name;
   }

   // Getters and Setters
}

enum Type {
   TYPE1,
   TYPE2
}

I have a list of those Subject classes

List<Subject> subjects = Arrays.asList(
    new Subject(1, Type.TYPE1, "South", "Oscar"),
    new Subject(2, Type.TYPE2, "South", "Robert"),
    new Subject(3, Type.TYPE2, "North", "Dan"),
    new Subject(4, Type.TYPE2, "South", "Gary"));

I would like to get as a result of using Collectors.groupingBy() a Map grouping first the Subject objects by Subject.origin and then grouped by Subject.type

Getting as a result an object like this Map<String, Map<Type, List<Subject>>>

like image 444
alexzm1 Avatar asked Jun 13 '15 23:06

alexzm1


People also ask

How does Collector groupingBy work?

The groupingBy() method of Collectors class in Java are used for grouping objects by some property and storing results in a Map instance. In order to use it, we always need to specify a property by which the grouping would be performed. This method provides similar functionality to SQL's GROUP BY clause.

What is the purpose of the MAP method in Java 8 streams?

Java 8 Stream's map method is intermediate operation and consumes single element forom input Stream and produces single element to output Stream. It simply used to convert Stream of one type to another.

What implementation of list does the collectors toList () create?

The toList() method of Collectors Class is a static (class) method. It returns a Collector Interface that gathers the input data onto a new list. This method never guarantees type, mutability, serializability, or thread-safety of the returned list but for more control toCollection(Supplier) method can be used.


2 Answers

groupingBy accepts a downstream collector, which can also be a groupingBy:

subjects.stream()
        .collect(groupingBy(
                Subject::getOrigin, 
                groupingBy(Subject::getType)    
        ));
like image 196
Misha Avatar answered Oct 11 '22 03:10

Misha


Stream<Subject> subjects = Stream.of(
  new Subject(1, Subject.Type.TYPE1, "South", "Oscar"), 
  new Subject(2, Subject.Type.TYPE2, "South", "Robert"),
  new Subject(3, Subject.Type.TYPE2, "North", "Dan"), 
  new Subject(4, Subject.Type.TYPE2, "South", "Gary"));




Map<String, Map<Subject.Type, List<Subject>>>  subjectByOriginByType;
subjectByOriginByType = subjects.collect(Collectors.groupingBy(
        s->s.getOrigin(), Collectors.groupingBy(
        s->s.getType(), 
        Collectors.mapping((Subject s) -> s, Collectors.toList()))));
like image 29
frhack Avatar answered Oct 11 '22 04:10

frhack