2015-02-03 4 views
5

Ich habe eine Liste von Listen eines bestimmten Objekts und ich möchte alle Elemente der Listen basierend auf einer bestimmten Instanzvariable hinzufügen.Java 8 - Wie summiere ich alles Listenelement in einer Liste von Listen

Mein Objekt:

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]; 
    } 
} 

ich aus der Datenbank eine Liste von Arrays vom Typ Objekt erhalten:

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

Ich benutze Java 8 bis Gruppe meiner Daten von ID, weil ich will SUM von riskValue alle Objekte des Typs Risk mit der gleichen id. Diese

ist, was ich tue:

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

An dieser Stelle ich mein Risiko alle Objekte nach ID gruppiert. Und ich will für jede Liste alle Objekte von riskValue summieren und die Gesamt haben in der Variablen totRisk

Wie in der Variablen totRisk die Summe der Variablen riskValue in jeder Liste berechnen?

Anmerkung1: Ich möchte es mit Java 8 tun, ich weiß, wie es mit Java 7 und darunter zu tun.

Anmerkung2: Vielleicht ist es auch möglich, dies auf einmal zu tun, indem Sie nicht zuerst nach ID gruppieren müssen. Was ich erreichen möchte ist, alle Objekte mit der gleichen ID im Original List<Object[]> results zu summieren. Wenn es mit nur einer Aussage gemacht werden kann, ist es noch besser.

Antwort

7

Sie müssen beachten, dass Sie Collector s kombinieren können. Siehe Collectors.groupingBy(Function,Collector)

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

Sie auch mit der ersten Operation kombinieren:

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

Bitte beachte, dass ich davon ausgehen, dass Sie eine Methode getRiskValue() in Ihrer Klasse haben Risk, sonst Sie Risk::getRiskValue mit einem Lambda ersetzen Ausdruck r -> r.riskValue für den Zugriff auf das Feld, jedoch mit Getter-Methoden wird immer empfohlen.

Das Ergebnis wird von ID bis Summe abgebildet.


Nach Ihrer Frage wieder zu lesen, bemerkte ich, dass Sie riskValue tatsächlich summieren wollen und speichern sie in totRisk von jeder (?) Risk Instanz. Dies ist ein wenig komplizierter, da es nicht das gemeinsame Nutzungsmuster paßt:

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; 
    }))); 

wir an dieser Stelle wirklich zu verwenden import static java.util.stream.Collectors.*; wechseln sollen:

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

Nur sicher sein: Karte es ist eine Karte von "id": "total" für diese ID, oder? – horus

+1

Sie haben Recht, es ist Mapping auf 'total' – Holger

+0

letzte Sache: Lambda Ausdruck wie oben beschrieben zu verwenden, indem Sie ** Risk :: getTotRisk ** mit ** r -> r.totRisk ** funktioniert nicht für mich (es kompiliert nicht). Ist es möglich, es mit einer Lamba zu erreichen, ohne den Getter zu kreieren? – horus

Verwandte Themen