2015-06-22 14 views
5

Per il bene di questo esempio, supponiamo che ho un tipo semplice Tuple con due attributi:valori mappa in Collectors.groupingBy()

interface Tuple<T, U> { 
    T getFirst(); 
    U getSecond(); 
} 

Ora voglio trasformare una collezione di (first, second) tuple in una mappa che associa ogni valore first a un insieme di tutti i valori second contenuti in tuple con quello specifico valore first. Il metodo groupSecondByFirst() mostra una possibile implementazione facendo quello che voglio:

<T, U> Map<T, Set<U>> groupSecondByFirst(Set<Tuple<T, U>> tuples) { 
    Map<T, Set<U>> result = new HashMap<>(); 

    for (Tuple<T, U> i : tuples) { 
     result.computeIfAbsent(i.getFirst(), x -> new HashSet<>()).add(i.getSecond()); 
    } 

    return result; 
} 

Se l'ingresso era [(1, "one"), (1, "eins"), (1, "uno"), (2, "two"), (3, "three")] l'uscita sarebbe { 1 = ["one", "eins", "uno"], 2 = ["two"], 3 = ["trhee"] }

Vorrei sapere se e come posso realizzare questo utilizzando il framework flussi. Il migliore che ho è la seguente espressione, che restituisce una mappa che contiene l'intera tupla come valori e non solo loro second elementi:

Map<T, Set<Tuple<T, U>>> collect = tuples.stream().collect(
    Collectors.groupingBy(Tuple::getFirst, Collectors.toSet())); 

risposta

13

ho trovato una soluzione; Si tratta di Collections.mapping(), che può racchiudere un raccoglitore e applica una funzione di mappatura che viene applicata a tutti gli elementi prima di essere inviati al raccoglitore incartato:

static <T, U> Map<T, Set<U>> groupSecondByFirst(Collection<Tuple<T, U>> tuples) { 
    return tuples 
     .stream() 
     .collect(
      Collectors.groupingBy(
       Tuple::getFirst, 
       Collectors.mapping(
        Tuple::getSecond, 
        Collectors.toSet()))); 
} 
Problemi correlati