2015-05-06 12 views
21

Ich möchte das Äquivalent von dieser mit einem Strom:Wie summiere ich Werte in einer Map mit einem Stream?

public static <T extends Number> T getSum(final Map<String, T> data) { 
    T sum = 0; 
    for (String key: data.keySet()) 
     sum += data.get(key); 
    return sum; 
} 

Dieser Code kompiliert nicht eigentlich da 0 nicht zugeordnet werden können T geben, aber Sie bekommen die Idee.

+1

Sie können einfach nicht tun, weil Java akzeptiert keinen Operator Überladen für Klassen. –

+1

Ich verstehe die Idee nicht. Was soll die Antwort sein, ein 'T' oder ein primitiver Typ wie' int'? –

+0

@pbabcdefp Integer, Double, oder es könnte int oder double sein – Jay

Antwort

41

Sie können dies tun:

int sum = data.values().stream().mapToInt(Number::intValue).sum(); 
+0

Super! Gibt es eine Möglichkeit, es generisch zu machen? – Jay

+2

@Jay Sie können den Mapper und den Sommer in übergeben. Sie würden mit etwas wie 'MyMath.sum (map, Number :: intValue, Integer :: sum)' enden und der Sommer ist ein Reduce-Vorgang. Das ist nicht viel besser, also nicht wirklich. – Radiodef

+1

@Jay Es ist bereits generisch in dem Sinne, dass 'T' ein Typ ist, der' Nummer' erweitert. Wenn du meinst, gibt es eine Möglichkeit, es zu einem "int" oder einem "double" usw. zu machen, ist die Antwort nein, da primitive Typen in Java separat behandelt werden müssen. –

10

Hier ist eine andere Art und Weise, die geringfügig kürzer ist:

int sum = data.values().stream().reduce(0, Integer::sum); 

Ich habe darüber nachgedacht, und ich sehe nicht wirklich einen Weg, es generisch machen das ist eigentlich bequemer als die Ideen hier.

Wir könnten etwas tun:

static <T> T sum(Map<?, T> m, BinaryOperator<T> summer) { 
    return m.values().stream().reduce(summer).get(); 
} 

int sum = MyMath.sum(data, Integer::sum); 

Aber Sie immer den Sommer vorbei am Ende und reduce ist auch problematisch, weil es Optional zurückgibt. (Die obige sum Methode löst eine Ausnahme für eine leere Karte, aber eine leere Summe sollte 0 sein)

+1

gibt es auch keine generische Lösung, um heterogene Zahlenströme (AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, ...) und möglicherweise benutzerdefinierte Typen zu summieren – harshtuna

+0

@harshtuna Ja es gibt wirklich keine gute Lösung hier IMO. Java könnte tun, um eine Schnittstelle hinzuzufügen, die Arithmetik in der Bibliothek ermöglicht. – Radiodef

+0

Die Argumente für 'Integer.sum' sind beide' int', also musst du im ersten Bit irgendwie von 'T' nach' int' gehen. Ich denke, die Lösung für das 'Optional'-Problem besteht darin, die Methode dazu zu bringen, einen Nullwert zu akzeptieren und' orElse' zu ​​verwenden. –

0

Sie es wie folgt tun:

int creditAmountSum = result.stream().map(e -> e.getCreditAmount()).reduce(0, (x, y) -> x + y); 
Verwandte Themen