简体   繁体   English

如何将整数列表与 java 流相加?

[英]How to sum a list of integers with java streams?

I want to sum a list of Integers.我想总结一个整数列表。 It works as follows, but the syntax does not feel right.它的工作原理如下,但语法感觉不对。 Could the code be optimized?代码可以优化吗?

Map<String, Integer> integers;
integers.values().stream().mapToInt(i -> i).sum();

This will work, but the i -> i is doing some automatic unboxing which is why it "feels" strange.这会起作用,但是i -> i正在执行一些自动拆箱操作,这就是为什么它“感觉”很奇怪。 mapToInt converts the stream to an IntStream "of primitive int-valued elements". mapToInt将流转换为“原始 int 值元素的IntStream ”。 Either of the following will work and better explain what the compiler is doing under the hood with your original syntax:以下任一方法都可以使用并更好地解释编译器在使用您的原始语法进行的工作:

integers.values().stream().mapToInt(i -> i.intValue()).sum();
integers.values().stream().mapToInt(Integer::intValue).sum();

I suggest 2 more options:我建议另外 2 个选项:

integers.values().stream().mapToInt(Integer::intValue).sum();
integers.values().stream().collect(Collectors.summingInt(Integer::intValue));

The second one uses Collectors.summingInt() collector, there is also a summingLong() collector which you would use with mapToLong .第二个使用Collectors.summingInt()收集器,还有一个summingLong()收集器,您可以将其与mapToLong一起使用。


And a third option: Java 8 introduces a very effective LongAdder accumulator designed to speed-up summarizing in parallel streams and multi-thread environments.第三个选项:Java 8 引入了一个非常有效的LongAdder累加器,旨在加速并行流和多线程环境中的汇总。 Here, here's an example use:在这里,这是一个使用示例:

LongAdder a = new LongAdder();
map.values().parallelStream().forEach(a::add);
sum = a.intValue();

From the docs文档

Reduction operations A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list.归约运算 归约运算(也称为折叠)采用一系列输入元素,并通过重复应用组合运算将它们组合成单个汇总结果,例如求一组数字的总和或最大值,或将元素累加为一个列表。 The streams classes have multiple forms of general reduction operations, called reduce() and collect(), as well as multiple specialized reduction forms such as sum(), max(), or count().流类具有多种形式的通用归约操作,称为reduce() 和collect(),以及多种特殊归约形式,如sum()、max() 或count()。

Of course, such operations can be readily implemented as simple sequential loops, as in:当然,这样的操作可以很容易地实现为简单的顺序循环,如:

 int sum = 0; for (int x : numbers) { sum += x; }

However, there are good reasons to prefer a reduce operation over a mutative accumulation such as the above.然而,有充分的理由更喜欢减少操作而不是像上面那样的突变累积。 Not only is a reduction "more abstract" -- it operates on the stream as a whole rather than individual elements -- but a properly constructed reduce operation is inherently parallelizable, so long as the function(s) used to process the elements are associative and stateless.不仅reduce“更抽象”——它作为一个整体而不是单个元素对流进行操作——而且一个正确构造的reduce操作本质上是可并行化的,只要用于处理元素的函数是关联的和无国籍。 For example, given a stream of numbers for which we want to find the sum, we can write:例如,给定一个我们想要求和的数字流,我们可以这样写:

 int sum = numbers.stream().reduce(0, (x,y) -> x+y);

or:或者:

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

These reduction operations can run safely in parallel with almost no modification:这些归约操作几乎不需要修改就可以安全地并行运行:

 int sum = numbers.parallelStream().reduce(0, Integer::sum);

So, for a map you would use:因此,对于地图,您将使用:

integers.values().stream().mapToInt(i -> i).reduce(0, (x,y) -> x+y);

Or:或者:

integers.values().stream().reduce(0, Integer::sum);

You can use reduce method:您可以使用减少方法:

long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, (x, y) -> x + y);

or或者

long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, Integer::sum);

您可以使用reduce()对整数列表求和。

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

You can use collect method to add list of integers.您可以使用 collect 方法添加整数列表。

List<Integer> list = Arrays.asList(2, 4, 5, 6);
int sum = list.stream().collect(Collectors.summingInt(Integer::intValue));

This would be the shortest way to sum up int type array (for long array LongStream , for double array DoubleStream and so forth).这将是总结int类型数组的最短方法(对于long数组LongStream ,对于double数组DoubleStream等等)。 Not all the primitive integer or floating point types have the Stream implementation though.不过,并非所有原始整数或浮点类型都具有Stream实现。

IntStream.of(integers).sum();

I have declared a list of Integers.我已经声明了一个整数列表。

ArrayList<Integer> numberList = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));

You can try using these different ways below.您可以尝试使用以下这些不同的方法。

Using mapToInt使用mapToInt

int sum = numberList.stream().mapToInt(Integer::intValue).sum();

Using summarizingInt使用summarizingInt

int sum = numberList.stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum();

Using reduce使用reduce

int sum = numberList.stream().reduce(Integer::sum).get().intValue();

May this help those who have objects on the list.愿这对那些在清单上有对象的人有所帮助。

If you have a list of objects and wanted to sum specific fields of this object use the below.如果您有一个对象列表并想对该对象的特定字段求和,请使用以下内容。

List<ResultSom> somList = MyUtil.getResultSom();
BigDecimal result= somList.stream().map(ResultSom::getNetto).reduce(
                                             BigDecimal.ZERO, BigDecimal::add);

There is one more option no one considered here and it reflects on usage of multi-core environment.这里还有一个没有人考虑的选项,它反映了多核环境的使用。 If you want to use its advantages, then next code should be used instead of the other mentioned solutions:如果你想利用它的优势,那么应该使用下一个代码而不是其他提到的解决方案:

int sum = integers.values().parallelStream().mapToInt(Integer::intValue)
        .reduce(0, Integer::sum, Integer::sum);

This solution is similar to other ones, but please notice the third argument in reduce.此解决方案与其他解决方案类似,但请注意 reduce 中的第三个参数。 It tells compiler what to do with partial summaries calculated in different chunks of the stream, by different threads.它告诉编译器如何处理不同线程在 stream 的不同块中计算的部分摘要。 Also instead of stream() , the parallelStream() is used.同样代替stream() ,使用了parallelStream() In this case it would just summarize it.在这种情况下,它只会对其进行总结。 The other option to put as third argument is (i, j) -> i + j , which means that it would add a value of a stream chunk ( j ) to the current value ( i ) and use it as a current value for the next stream chunk until all partial results are processed.作为第三个参数的另一个选项是(i, j) -> i + j ,这意味着它会将 stream 块的值 ( j ) 添加到当前值 ( i ) 并将其用作当前值下一个 stream 块,直到处理完所有部分结果。

Even when using plain stream() it is useful to tell to reduce what to do with stream chunks' summaries, just in case someone, or you, would like to parallelize it in the future.即使在使用纯stream()时,告诉减少如何处理 stream 块的摘要也是有用的,以防万一有人或您将来想并行化它。 The initial development is best time for that, since later on you need to remember what this is supposed to be and need to spend some time in understanding the purpose of that code again.最初的开发是最好的时机,因为稍后您需要记住它应该是什么,并且需要花一些时间再次理解该代码的用途。

And of course instead of method reference operator you can have different dialect of lambda. I prefer it this way as more compact and still easy readable.当然,除了方法引用运算符,您还可以使用 lambda 的不同方言。我更喜欢这种方式,因为它更紧凑且易于阅读。

Also remember this can be used for more complex calculations too, but always be aware there are no guarantees about sequence and deployment of stream elements to threads.还要记住,这也可以用于更复杂的计算,但请始终注意,不能保证 stream 元素到线程的顺序和部署。

Unfortunately looks like the Stream API only returns normal streams from, say, List<Integer>#stream() .不幸的是,Stream API 只从List<Integer>#stream()返回普通流。 Guess they're pretty much forced to because of how generics work.猜猜他们是被迫的,因为泛型是如何工作的。

These normal Streams are of generic objects so don't have specialized methods like sum() etc. so you have to use the weird re-stream "looks like a no-op" conversion by default to get to those methods... .mapToInt(i -> i) .这些正常的流是通用对象所以没有特殊的方法,如sum()等,所以你必须在默认情况下使用怪异再流“看起来像一个空操作”的转换来获得这些方法...... .mapToInt(i -> i)

Another option is using " Eclipse Collections " which are like an expanded java Stream API另一种选择是使用“ Eclipse Collections ”,它就像一个扩展的java Stream API

IntLists.immutable.ofAll(integers.values()).sum();

List < Integer > listOfIntegers = List.of(1, 2, 10, 3, 4, 8, 5, 9, 6, 7);

Optional < Integer > maxValue = listOfIntegers
  .stream().reduce((partialResult, currentValue) -> Math.max(partialResult, currentValue));

System.out.println("Maximum value : " + maxValue);

Output: Maximum value: Optional[10]输出:最大值:可选[10]

IntStream.of(1, 2, 23).sum();
IntStream.of(1, 2, 23,1, 2, 23,1, 2, 23).max().getAsInt();
class Pojo{
    int num;

    public Pojo(int num) {
        super();
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

List<Pojo> list = new ArrayList<Pojo>();
            list.add(new Pojo(1));
            list.add(new Pojo(5));
            list.add(new Pojo(3));
            list.add(new Pojo(4));
            list.add(new Pojo(5));

            int totalSum = list.stream().mapToInt(pojo -> pojo.getNum()).sum();
            System.out.println(totalSum);

Most of the aspects are covered.涵盖了大部分方面。 But there could be a requirement to find the aggregation of other data types apart from Integer, Long(for which specialized stream support is already present).但是可能需要找到除 Integer、Long(已经存在专门的流支持)之外的其他数据类型的聚合。 For eg stram with BigInteger For such a type we can use reduce operation like例如,带有 BigInteger 的 stram 对于这种类型,我们可以使用 reduce 操作,例如

list.stream().reduce((bigInteger1, bigInteger2) -> bigInteger1.add(bigInteger2)) list.stream().reduce((bigInteger1, bigInteger2) -> bigInteger1.add(bigInteger2))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM