How to sum values in a Map with a stream?

2019-01-23 01:12发布

问题:

I want the equivalent of this with a 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;
}

This code doesn't actually compile because 0 cannot be assigned to type T, but you get the idea.

回答1:

You can do this:

int sum = data.values().stream().mapToInt(Integer::parseInt).sum();


回答2:

Here's another way to do this:

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

(For a sum to just int, however, Paul's answer does less boxing and unboxing.)

As for doing this generically, I don't think there's a way that's much more convenient.

We could do something like this:

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

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

But you always end up passing the summer. reduce is also problematic because it returns Optional. The above sum method throws an exception for an empty map, but an empty sum should be 0. Of course, we could pass the 0 too:

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

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


回答3:

You can do it like this:

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