Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using groupingBy to create a Map with immutable list as the key

Tags:

java

java-8

Say, I've a class called Project,

class Project {
    private String projectId;
    private String projectName;
}

and a class called Employee, which has a list of projects

class Employee {
    private String name;
    private List<Project> projects
}

I also have a list of Employee objects. Now, I need to create a Map with the list of projects as the key and a set of employee objects as the value from this list. I can get it working by

Map<List<Project>, Set<Employee>> x =
        employees
        .stream
        .collect(Collectors.groupingBy(Employee::getProjects, Collectors.toSet()));

However, since I'm using List as the key, I want to be extra careful and make sure that the list is immutable. Is there a way to achieve this?

Thanks.

like image 768
cdoe Avatar asked Oct 13 '17 11:10

cdoe


2 Answers

This is how you would do it with Guava (I tried it with version 24.1, which is the latest one as of today)

List<Employee> employees = new ArrayList<>();

//  ... let's assume someone fills in the employees

// Everything mutable
Map<List<Project>, Set<Employee>> x =
    employees
        .stream()
        .collect(Collectors.groupingBy(Employee::getProjects, Collectors.toSet()));

// Everything immutable
ImmutableMap<ImmutableList<Project>, ImmutableSet<Employee>> immutableX =
    employees
        .stream()
        .collect(
            Collectors.collectingAndThen(
                Collectors.groupingBy(
                    (employee) -> ImmutableList.copyOf(employee.getProjects()),
                    ImmutableSet.<Employee>toImmutableSet()),
                ImmutableMap::copyOf));

// Only the List<Project> immutable
Map<ImmutableList<Project>, Set<Employee>> immutableListX =
    employees
        .stream()
        .collect(
            Collectors.groupingBy(
                (employee) -> ImmutableList.copyOf(employee.getProjects()),
                Collectors.toSet()));

This assumes your classes definitions are these (I needed to add the method getProjects for the original example to compile):

class Project {
  public String projectId;
  public String projectName;
}

class Employee {
  public String name;
  public List<Project> projects;

  public List<Project> getProjects() {
    return projects;
  }
}
like image 127
epere4 Avatar answered Oct 17 '22 04:10

epere4


List immutability is supported in Java 9. You can simply change Employee#getProjects to the following:

public List<Project> getProjects() {
    return List.of(projects.toArray(new Project[projects.size()]));
}

If you don't want this method to return an immutable List, then you can change the Collector:

employees.stream()
         .collect(Collectors.groupingBy(e -> List.of(e.getProjects().toArray(new Project[0])), Collectors.toSet()));
like image 45
Jacob G. Avatar answered Oct 17 '22 03:10

Jacob G.