Есть ли лучший способ сделать частичные суммы элементов массива в JavaScript?

Интересно, есть ли лучший способ создания более эффективного решения для частичных сумм массива.

Учитывая массив, скажем, x = [ 0, 1, 2, 3, 4, 5 ], я сгенерировал вложенные массивы элементов, а затем вычислил сумму каждого массива, которая дает:

[ 0, 1, 3, 6, 10, 15 ]

Итак, полный код:

x.map((y,i)=>x.filter((t,j)=>j<=i))
 .map(ii=>ii.reduce((x,y)=>x+y,0))

Интересно, будет ли у плоской карты или какого-либо другого метода массива решение, которое не требует расширения каждого подмассива.

Ответы

Ответ 1

Многое, сохраняя промежуточный итог:

function* partialSums(iterable) {
    let s = 0;

    for (const x of iterable) {
        s += x;
        yield s;
    }
}

const x = [0, 1, 2, 3, 4, 5];
console.log(Array.from(partialSums(x)).join(', '));

Ответ 2

Ниже scan принимает функцию отображения f и начальный аккумулятор r -

const scan = (f, r, [ x, ...xs ]) =>
  x === undefined
    ? [ r ]
    : [ r, ...scan (f, f (r, x), xs) ]
  
const add = (x, y) =>
  x + y

const print = (...vs) =>
  vs .forEach (v => console .log (v))

const data =
  [ 0, 1, 2, 3, 4, 5 ]
  
print
  ( scan (add, 0, data)
  , scan (Math.max, 3, data)
  , scan (add, 0, [])
  )

// [ 0, 0, 1, 3, 6, 10, 15 ]
// [ 3, 3, 3, 3, 3, 4, 5 ]
// [ 0 ]

Ответ 3

Плоская карта не будет полезна в вашем случае, потому что вы не пытаетесь сгладить частичные результаты, поступающие в виде списков, но мы, вероятно, можем попытаться решить вашу проблему за один раз:

[0, 1, 2, 3, 4, 5]
.reduce(
   ([arr, sum], el) => { // We pass along array and running sum
       const next = sum + el
       return [[...arr, next], next]
   },
   [[], 0] // We need to seed our reduce with empty array and accumulator for calculating running sum
)[0] // Array containing array and the last sum is returned, so we need to take only the first element

Он также выполняет итерацию массива только один раз, поэтому он может быть немного более производительным, чем решение, создающее фрагменты и затем суммирующее их.

Или версия с array.push, которая использует тот же массив:

[0, 1, 2, 3, 4, 5]
.reduce(
   ([arr, sum], el) => { // We pass along array and running sum
       const next = sum + el
       arr.push(next)
       return [arr, next]
   },
   [[], 0] // We need to seed our reduce with empty array and accumulator for calculating running sum
)[0] 

Ответ 4

Вы можете просто использовать цикл for с переменной, чтобы отслеживать последнюю сумму

let x = [ 0, 1, 2, 3, 4, 5 ]

let sum = (arr) => {
  let sum = 0
  let final = []
  for(let i=0; i<arr.length; i++){
    sum+= arr[i]
    final.push(sum)
  }
  return final
}

console.log(sum(x))

Ответ 5

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

const array = [0, 1, 2, 3, 4, 5, 6];

const sums = array.reduce((acc,current,index) => {
  const prev = acc.length ? acc[index-1] : 0;
  acc.push(prev + current);
  return acc;
},[]);

console.log(sums.toString());

Ответ 6

Если вы спрашиваете, есть ли более быстрый или более эффективный способ, тогда других ответов достаточно.

Тем не менее, я бы сказал, что нечто похожее на ваше текущее решение проще для чтения и более декларативно, если мы сформулируем это как функцию отображения.

В частности, что-то вроде "Сопоставить каждое значение с самим собой плюс все предыдущие значения в массиве".

Вы могли бы использовать фильтр, как вы сделали в своем вопросе, но я думаю, что срез более понятен.

const x = [ 0, 1, 2, 3, 4, 5 ];

// A common generic helper function
const sum = (acc, val) => acc + val

const sums = x.map((val, i, self) => val + self.slice(0, i).reduce(sum, 0))

Ответ 7

Можно использовать карту напрямую, если вы сохраните переменную внешнего аккумулятора:

const x = [ 0, 1, 2, 3, 4, 5 ];

let acc = 0;
const prefixSum = x.map(x => acc += x);

console.log(prefixSum);

Ответ 8

Одним из вариантов является использование одного .map который использует .reduce внутри для суммирования нарезанного частичного массива:

const x = [0, 1, 2, 3, 4, 5];

const sum = (x, y) => x + y;
const partialSums = x.map((_, i, arr) => arr.slice(0, i + 1).reduce(sum));
console.log(partialSums);

Ответ 9

Вот простой ответ с использованием рекурсивной функции.

var array = [ 0, 1, 2, 3, 4, 5 ];

function sumArray(arrayToSum, index){
    if(index < arrayToSum.length-1){
        arrayToSum[index+1] = arrayToSum[index] + arrayToSum[index+1];
        return sumArray(arrayToSum, index+1);
  }else
    return arrayToSum;

}
sumArray(array, 0);

console.log(array);

Ответ 10

Можно использовать для каждого из них, а затем нарезать массивы, чтобы получить элементы по одному, а затем суммировать их все по array.reduce

let x = [0, 1, 2, 3, 4, 5]
let sum = []
x.forEach((_, index) => {
  index++;
  sum.push(x.slice(0, index).reduce((a, b) => a + b))
})
console.log(sum)