2015-02-03 31 views
5

Mam Mapę list określonego obiektu i chcę dodać wszystkie elementy list na podstawie konkretnej zmiennej instancji.Java 8 - Jak podsumować cały element listy na mapie list

mojego obiektu:

class Risk{ 
    Integer id, riskValue, totRisk=0; 
    String name; 

    Integer getId(){ 
     return id; 
    } 
    Risk(Object[] result){ 
     id=(Integer)result[0]; 
     riskValue=(Integer)result[1]; 
     name=(String)result[3]; 
    } 
} 

uzyskać z bazy danych listę tablic Typ obiektu:

List<Object[]> results=getResults(); 

używam Java 8 do grupy moich danych przez ID, bo chcę SUMA przez riskValue wszystkie obiekty typu Risk o tym samym id.

To co mam zrobić:

List<Risk> risks=results.stream().map(Risk::new).collect(Collectors.toList()); 
Map<Integer, List<Risk>> byId=risks.stream.collect(Collectors.groupingBy(Risk::getId)); 

W tym momencie mam wszystkie moje przedmioty ryzyka pogrupowane według ID. I chcę, dla każdej listy podsumować wszystkie obiekty przez riskValue i mają łącznie w zmiennej totRisk

Jak obliczyć w zmiennej totRisk sumy zmiennych riskValue w każdym liście?

Uwaga1: Chcę to zrobić za pomocą Java 8, wiem, jak to zrobić, używając Java 7 i poniżej.

Uwaga 2: Możliwe, że można to zrobić za jednym razem, ponieważ nie trzeba najpierw grupować według identyfikatora. Co chcę osiągnąć, to zsumować wszystkie obiekty o tym samym ID w oryginalnym List<Object[]> results. Jeśli można to zrobić za pomocą tylko jednej instrukcji, jest jeszcze lepiej.

Odpowiedz

7

Należy pamiętać, że można łączyć Collector s. Zobacz Collectors.groupingBy(Function,Collector)

Map<Integer, Integer> byId=risks.stream.collect(
    Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue))); 

Można również połączyć go z pierwszej operacji:

Map<Integer, Integer> byId=results.stream().map(Risk::new).collect(
    Collectors.groupingBy(Risk::getId, Collectors.summingInt(Risk::getRiskValue))); 

Zauważ, że zakładamy, że masz sposób getRiskValue() w swojej klasie Risk, w przeciwnym razie trzeba wymienić Risk::getRiskValue z lambda wyrażenie r -> r.riskValue dostęp do pola, jednak o metod getter jest zawsze zalecane.

Wynik mapuje od id do sumy.


Po ponownym przeczytaniu pytanie, zauważyłem, że rzeczywiście chcesz Podsumowując riskValue i przechowywać go w totRisk z każdej instancji (?) Risk. To jest nieco bardziej skomplikowany, gdyż nie pasowały do ​​korzystania ze wspólnego wzoru:

Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
    Collectors.groupingBy(Risk::getId, Collectors.collectingAndThen(
    Collectors.toList(), l-> { 
     int total=l.stream().collect(Collectors.summingInt(r -> r.riskValue)); 
     l.forEach(r->r.totRisk=total); 
     return l; 
    }))); 

w tym momencie naprawdę powinien przełączyć się za pomocą import static java.util.stream.Collectors.*;:

Map<Integer, List<Risk>> byId=results.stream().map(Risk::new).collect(
    groupingBy(Risk::getId, collectingAndThen(toList(), l-> { 
    int total=l.stream().collect(summingInt(r -> r.riskValue)); 
    l.forEach(r->r.totRisk=total); 
    return l; 
    }))); 
+0

Wystarczy mieć pewność: Mapa to mapa "id": "total" dla tego id, prawda? – horus

+1

Masz rację, mapuje się na 'total' – Holger

+0

ostatnia rzecz: używając wyrażenia lambda, jak pisałeś powyżej, zastępując ** Risk :: getTotRisk ** z ** r -> r.totRisk ** nie działa dla mnie (to nie kompiluje). Czy można to osiągnąć za pomocą lamby bez potrzeby tworzenia gettera? – horus

Powiązane problemy