Вычисление списка совокупных сумм из списка целых чисел с потоками Java

#java #lambda #java-8 #java-stream

#java #лямбда #java-8 #java-stream

Вопрос:

У меня есть следующий список :

  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
  

Мне нужно вычислить совокупную сумму — значение списка

 T(n) = T(n)   T(n-1) for n >0; 
and
T(0) = T(0)
  

Я хочу вычислить это с помощью Java stream API, чтобы я мог реализовать это с помощью Spark для вычисления больших данных. Я наивен в потоках Java, я попробовал несколько выражений, но ни одно из них не работает
эквивалентный структурированный код должен быть похож :

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

Комментарии:

1. Stream API здесь не приносит никакой пользы.

2. Какая связь между spark?

3. @Lamanus Я могу использовать это решение с некоторыми изменениями типа данных в JavaRDD в Spark

4. @Nikolas, я совершенно новичок в Stream API, не могли бы вы помочь мне понять, почему Stream не работает? как реализовать эту логику функциональным способом?

5. Потоки @NilKulkarni будут работать. Но это не дает дополнительной выгоды и фактически добавляет дополнительные накладные расходы.

Ответ №1:

Попробуйте это.

 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]
  

Комментарии:

1. спасибо, не могу проголосовать за повышение, у меня недостаточно репутации

2. Предпочтительный подход по сравнению с потоками, конечно. Но в OP было указано потоковое решение.

Ответ №2:

Вот два способа сделать это.

Первый вариант очень неэффективен, поскольку в основном использует вложенные циклы для накопления значений. Первый 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];
}
  

Суть в том, чтобы придерживаться того, что у вас есть.

Комментарии:

1. Спасибо. для меня это было своего рода открытием, потоки могут приносить пользу не каждый раз..

Ответ №3:

Вы можете попробовать использовать пользовательский сборщик.

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

   }