Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to process the resulting List<T> values of `groupingBy` in the same `stream()`?

Briefly: collect(groupingBy()) returns a map Map<K, List<T>>. How can I replace , for each K, the value List<T> by a new value (of class U) which is computed based on List<T>, and return Map<K, U> in the same stream()?


An example: Suppose I have a Task, which consists of a taskId and a list of Jobs:

public class Task { int taskId; List<Job> jobList; }

For each Job, method getAgentId determines an "agent" who is able to process it:

// in class Job
int getAgentId() { // return the "agent" who is responsible for @param job }

A Task is partitioned into multiple sub-Tasks such that each of them can be processed by a separate "agent":

// in class Partition; `Integer` for "agent" id
Map<Integer, Task> partition(Task task) { }

My attempt: I used groupingBy:

Map<Integer, Task> partition(Task task) {
    int id = task.getTaskId();
    Map<Integer, List<Job>> agentJobsMap = 
        task.getJobList().stream()
                         .collect(groupingBy(Job::getAgentId),
                                  // question here);
}

Question: However I want to return Map<Integer, Task> instead of Map<Integer, List<Job>>; that is, I want to wrap the resulting List<Job> of groupingBy into a new Task by new Task(id, the resulting List<Job>). How to do that? Or are there alternatives without groupingBy?

like image 460
hengxin Avatar asked Jan 07 '16 06:01

hengxin


1 Answers

Use the overload of groupingBy that accepts another Collector to use on the results:

task.getJobList().stream()
    .collect(
        groupingBy(
             Job::getAgentId,
             collectingAndThen(toList(), jobs -> new Task(id, jobs))));
like image 67
Louis Wasserman Avatar answered Sep 28 '22 05:09

Louis Wasserman