计算整数列表的累积和列表,使用Java流。

huangapple go评论72阅读模式
英文:

Calculating List of cumulative sums from List of integers with Java streams

问题

我有以下的列表:

 输入 :: 4 5 8 -11 9 5 -7 4 6 -6 -8 -11 80 -32 -56 -15 5 -49 

 输出 :: 4 9 17 6 15 20 13 17 23 17 9 -2 78 46 -10 -25 -20 -69

我需要计算累积和 - 列表含义

T(n) = T(n) + T(n-1),其中 n > 0;
并且
T(0) = T(0)

我想使用Java Stream API来计算,以便我可以在Spark中进行大数据计算。我对Java Streams不太了解,我尝试了几个表达式,但都没有起作用。
等价的结构化代码应该如下:

int[] numbers = {4, 5, 8, -11, 9, 5, -7, 4, 6,-6, -8, -11, 80, -32, -56, -15, 5, -49};
int temp = 0;

for (int i = 0; i < numbers.length; i++) {
   temp = temp + numbers[i];
   numbers[i] = temp;
}
英文:

I have the following list :

 INPUT :: 4 5 8 -11 9 5 -7 4 6 -6 -8 -11 80 -32 -56 -15 5 -49 

 OUTPUT :: 4 9 17 6 15 20 13 17 23 17 9 -2 78 46 -10 -25 -20 -69

I need to calculate cumulative sum - List meaning

T(n) = T(n) + T(n-1) for n &gt;0; 
and
T(0) = T(0)

I want to calculate that with Java stream API so that I can implement it with Spark for big data calculation. I am naive in Java Streams I have tried several expressions bt none of them is working
the equivalent stuctured code should be like :

int[] numbers = {4, 5, 8, -11, 9, 5, -7, 4, 6,-6, -8, -11, 80, -32, -56, -15, 5, -49};
int temp = 0;

for (int i = 0 ; i &lt; numbers.length ; i++) {
   temp = temp + numbers[i];
   numbers[i] = temp;
}

答案1

得分: 3

试试这个。

int[] a = {4, 5, 8, -11, 9, 5, -7, 4, 6, -6, -8, -11, 80, -32, -56, -15, 5, -49};
Arrays.parallelPrefix(a, (x, y) -> x + y);
System.out.println(Arrays.toString(a));

输出:

[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]
英文:

Try this.

int[] a = {4, 5, 8, -11, 9, 5, -7, 4, 6, -6, -8, -11, 80, -32, -56, -15, 5, -49};
Arrays.parallelPrefix(a, (x, y) -&gt; x + y);
System.out.println(Arrays.toString(a));

output:

[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]

答案2

得分: 0

这里有两种做法。

第一种非常低效,基本上使用了嵌套循环来累加值。第一个IntStream指定了值的范围,嵌套的IntStream创建了一个变量范围,并将从0累积到该范围末尾的值。

int[] result1 = IntStream.range(0, vals.length).map(
		i -> IntStream.rangeClosed(0, i).map(k -> vals[k]).reduce(0, (a, b) -> a + b))
		.toArray();

这种方法更符合常规方法。将一个包含单个0的数组串流化,然后使用它来累积值的运行总和。

int[] result2 = Stream.of(new int[] { 0 })
		.flatMapToInt(k -> IntStream.of(vals).map(v -> {
			k[0] += v;
			return k[0];
		})).toArray();

System.out.println(Arrays.toString(result1));
System.out.println(Arrays.toString(result2));

两者都打印出

[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]
[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]

但你简单地不能做得比这更好。

for (int i = 1; i < vals.length; i++) {
	  vals[i] += vals[i-1];
}

最重要的是坚持你现在所使用的方法。

英文:

Here are two ways of doing it.

The first is very inefficient as it basically uses nested loops to accumulate the values. The first IntStream specfies the range of values and the nested IntStream creates a variable range and sums up the values from 0 to the end of that range.

int[] result1 = IntStream.range(0, vals.length).map(
		i -&gt; IntStream.rangeClosed(0, i).map(k-&gt;vals[k]).reduce(0, (a, b) -&gt; a + b))
		.toArray();

This one is more in line with a more conventional method. Stream a single array of 0 and then use that to accumulate a running sum of the values.

int[] result2 = Stream.of(new int[] { 0 })
		.flatMapToInt(k -&gt; IntStream.of(vals).map(v -&gt; {
			k[0] += v;
			return k[0];
		})).toArray();

System.out.println(Arrays.toString(result1));
System.out.println(Arrays.toString(result2));

Both print

[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]
[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]

But you simply can't do any better than this.

for (int i = 1; i &lt; vals.length; i++) {
	  vals[i] += vals[i-1];
}

Bottom line is to stick with what you have.

答案3

得分: 0

你可以尝试使用自定义收集器。

public static void main(String[] args) {
    List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
    List<Integer> cumulatives = integers.stream().collect(CumulativeAdd.collector());
}

private static final class CumulativeAdd {

    List<Integer> retArray = new ArrayList<>();
    int sum = 0;

    public void accept(Integer num) {
        sum += num;
        retArray.add(sum);
    }

    public CumulativeAdd combine(CumulativeAdd other) {
        throw new UnsupportedOperationException("Parallel Stream not supported");
    }

    public List<Integer> finish() {
        return retArray;
    }

    public static Collector<Integer, ?, List<Integer>> collector() {
        return Collector.of(CumulativeAdd::new, CumulativeAdd::accept, CumulativeAdd::combine, CumulativeAdd::finish);
    }

}
英文:

You can try using a custom collector.

public static void main(String[] args) {
       List&lt;Integer&gt; integers = Arrays.asList(1, 2, 3, 4, 5);
       List&lt;Integer&gt; cumulatives = integers.stream().collect(CumulativeAdd.collector());
}
     private static final class CumulativeAdd {

       List&lt;Integer&gt; retArray= new ArrayList&lt;&gt;();
       int sum = 0; 

       public void accept(Integer num) {
           sum +=num;
           retArray.add(sum);
       }

       public CumulativeAdd combine(CumulativeAdd other) {
           throw new UnsupportedOperationException(&quot;Parallel Stream not supported&quot;);
       }

       public List&lt;Integer&gt; finish() {
           return retArray;
       }

       public static Collector&lt;Integer, ?, List&lt;Integer&gt;&gt; collector() {
           return Collector.of(CumulativeAdd::new, CumulativeAdd::accept, CumulativeAdd::combine, CumulativeAdd::finish);
       }

   }

huangapple
  • 本文由 发表于 2020年8月20日 21:07:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/63505820.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定