Java create multiple lists with duplicate elements from stream

I’m attempting to take a list and return a Map<String, List<String> containing certain aspects of the original list, where the original elements could occur multiple times as values under different keys using streams. For example:

class Employee {
  String firstName;
  String lastName;
  Status status;
}

enum Status {
  FULL_TIME,
  PART_TIME
}

List<Employee> employees = List.of(
  new Employee("f1", "l1", Status.PART_TIME),
  new Employee("f2", "l2", Status.FULL_TIME),
  new Employee("f3", "l3", Status.PART_TIME),
  new Employee("f4", "l4", Status.FULL_TIME));

The resulting map should have keys like the following and lists need to be immutable:

fName: ["f1", "f2", "f3", "f4"],
lName: ["l1", "l2", "l3", "l4"],
fullTime: ["f2 l2", "f4 l4"]

This would be easy with multiple streams, but the original data is quite large, so am trying to do it in one pass. I also have Guava and Apache Commons available if there is another method I’m not aware of. Thanks!

Edit 1: show how I’m doing it now

Here is what I’m doing in three streams that I’d like to simplify to one:

var firstName = employees.stream()
        .map(e -> e.getFirstName())
        .collect(Collectors.toUnmodifiableList());
var lastName = employees.stream()
        .map(e -> e.getLastName())
        .collect(Collectors.toUnmodifiableList());
var fullTime = employees.stream()
        .filter(e -> e.getStatus().equals(Status.FULL_TIME))
        .collect(Collectors.toUnmodifiableList());

Answer

You can convert the employee object to list of pairs where the pair key is the map key and the pair value is single value of the list. Then you can “group by” the pairs by the key.

Map<String, List<String>> vals = employees.stream()
  .map(e -> Arrays.asList(
    Pair.of("fname", e.firstName),
    Pair.of("lname", e.lastName),
    e.status == Status.FULL_TIME ? Pair.of("fullTime", e.firstName + " " + e.lastName) : null
  ))
  .flatMap(Collection::stream)
  .filter(Objects::nonNull)
  .collect(Collectors.groupingBy(p -> p.getLeft(), 
           Collectors.mapping(p -> p.getRight(), Collectors.toUnmodifiableList())));

However the memory consumption of this solution is worse than the one in the my previous answer, specially when dealing with large streams.

Leave a Reply

Your email address will not be published. Required fields are marked *