2016-01-07 9 views
5

Kurz:collect(groupingBy()) gibt eine Karte Map<K, List<T>>. Wie kann ich ersetzen, für jeden K, den Wert List<T> durch einen neuen Wert (der Klasse U), die auf List<T> Basis berechnet wird, und das Rück Map<K, U> im gleichenstream()?Wie verarbeitet man die resultierenden Liste <T> Werte von `groupingBy` in der gleichen` stream() `?


Ein Beispiel: Angenommen, habe ich ein Task, die aus einem taskId und einer Liste der Job s besteht:

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

Für jeden Job, Methode getAgentId bestimmt einen "Agenten" Wer kann es verarbeiten:

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

A Task ist in mehrere Unter Task s aufgeteilt, so dass jedes von ihnen kann durch einen separaten "agent" verarbeitet werden:

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

Mein Versuch: I groupingBy verwendet:

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

Frage: Ich möchte jedoch Map<Integer, Task> anstelle von Map<Integer, List<Job>> zurückgeben; das heißt, ich möchte den resultierenden List<Job> von groupingBy in einen neuen Task von new Task(id, the resulting List<Job>) einwickeln. Wie geht das? Oder gibt es Alternativen ohne groupingBy?

+1

Louis' Antwort mit 'collectingAndThen' durchaus sinnvoll ist. Im Allgemeinen würde ich es jedoch vermeiden, das Ziel "im selben Strom" zu weit zu gehen. Chaining ist nett, aber es kann so stark gedrängt werden, dass es verschleiert, was vor sich geht. Wir sehen häufig, dass Menschen versuchen, zwei Stromrohrleitungen zu "demselben Strom" zu machen (indem sie das Ergebnis einer Terminaloperation verketten), wenn es klarer wäre, einfach zuzugeben, was tatsächlich vor sich geht. Das Ziel sollte Klarheit, nicht "die Anzahl der Semikola minimieren." –

Antwort

8

Verwenden Sie die Überlastung von groupingBy, die eine andere Collector nimmt über die Ergebnisse zu nutzen:

task.getJobList().stream() 
    .collect(
     groupingBy(
      Job::getAgentId, 
      collectingAndThen(toList(), jobs -> new Task(id, jobs)))); 
+3

Sehr schöner Code! Danke, dass du immer so hilfsbereit bist. (Nur eine kleine Schreibweise: "job" sollte "jobs" sein; ich kann es nicht bearbeiten, weil nur ein einzelnes Zeichen hinzugefügt wird und stackoverflow darüber klagt.) – hengxin