Создание массива суммарной суммы в javascript

Это пример того, что мне нужно сделать:

var myarray = [5, 10, 3, 2];

var result1 = myarray[0];
var result2 = myarray[1] + myarray[0];
var result3 = myarray[2] + myarray[1] + myarray[0];
var result4 = myarray[3] + myarray[2] + myarray[1] + myarray[0];

так что все, что будет выводить 5, 15, 18, 20

но вместо того, чтобы записывать все подобные вамры, я хочу, чтобы он сказал что-то вроде:

var result = arrayitem + the sum of any previous items 

Это имеет смысл? Это возможно? Как мне это сделать?

Ответы

Ответ 1

Javascript reduce предоставляет текущий индекс, который здесь полезен:

var myarray = [5, 10, 3, 2];
var new_array = [];
myarray.reduce(function(a,b,i) { return new_array[i] = a+b; },0);
new_array // [5, 15, 18, 20]

Ответ 2

Альтернативный подход reduce, который позволяет избежать создания новых массивов:

var result = myarray.reduce(function(r, a) {
  r.push((r.length && r[r.length - 1] || 0) + a);
  return r;
}, []);

Нет необходимости повторно суммировать подмассивы для каждого результата.

отредактируйте менее уродливую версию того же самого:

var result = myarray.reduce(function(r, a) {
  if (r.length > 0)
    a += r[r.length - 1];
  r.push(a);
  return r;
}, []);

Ответ 3

Элегантное решение, скопированное с Нины Шольц, с использованием карри для доступа к предыдущему значению.

const cumulativeSum = (sum => value => sum += value)(0);

console.log([5, 10, 3, 2].map(cumulativeSum));

Ответ 4

Еще несколько вариантов с расширением массива ES6

[1, 2, 3].reduce((a, x, i) => [...a, x + (a[i-1] || 0)], []); //[1, 3, 6]

или

[3, 2, 1].reduce((a, x, i) => [...a, a.length > 0 ? x + a[i-1] : x], []); //[3, 5, 6]

Ответ 5

Простое решение с использованием ES6

let myarray = [5, 10, 3, 2];
    let new_array = [];  
    myarray.reduce( (prev, curr,i) =>  new_array[i] = prev + curr , 0 )
    console.log(new_array);

Ответ 6

Как насчет это решение

var new_array = myarray.concat(); //Copy initial array

for (var i = 1; i < myarray.length; i++) {
  new_array[i] = new_array[i-1] + myarray[i];
}

console.log(new_array);

PS: Вы также можете использовать исходный массив. Я просто скопировал его, если мы не хотим его загрязнять.

Ответ 7

Более общее (и эффективное) решение:

Array.prototype.accumulate = function(fn) {
    var r = [this[0]];
    for (var i = 1; i < this.length; i++)
        r.push(fn(r[i - 1], this[i]));
    return r;
}

или

Array.prototype.accumulate = function(fn) {
    var r = [this[0]];
    this.reduce(function(a, b) {
        return r[r.length] = fn(a, b);
    });
    return r;
}

а затем

r = [5, 10, 3, 2].accumulate(function(x, y) { return x + y })

Ответ 8

используйте сокращение, чтобы построить результат напрямую и без разрушения.

a.reduce(function(r,c,i){ r.push((r[i-1] || 0) + c); return r }, [] );

Ответ 9

Простое решение, использующее для цикла

var myarray = [5, 10, 3, 2];

var output = [];
var sum = 0;

for(var i in myarray){
  sum=sum+myarray[i];
  output.push(sum)
}
console.log(output)

https://jsfiddle.net/p31p877q/1/

Ответ 10

Еще одно чистое однострочное решение с уменьшением и concat

var result = myarray.reduce(function(a,b,i){ return i === 0 ?  [b]: a.concat(a[i-1]+b);},0);
//[5, 10, 3, 2] => [5, 15, 18, 20]

Ответ 11

Моя первоначальная мысль ES6 была похожа на несколько приведенных выше ответов Taeho и других.

const cumulativeSum = ([head, ...tail]) =>
   tail.reduce((acc, x, index) => {
      acc.push(acc[index] + x);
      return acc
  }, [head])
console.log(cumulativeSum([-1,2,3])

Решение выполняет:

n поисков, n - 1 сумма и 0 условных оценок

Большая часть того, что я видел выше, похоже, использовала:

n поисков, 2n сумм и n условных оценок:

Вы можете сделать это с ie6 safe js. Это, возможно, более эффективно, так как вам не нужно создавать массив хвостового спреда.

function cumulativeSum(a) {
    var result = [a[0]];
    var last = a[0];
    for (i = 1; i < a.length; i++) {
        last = last + a[i];
        result.push(last)
    }
    return result;
}
console.log(cumulativeSum([-1,2,3]))

Ответ 12

Простая функция, использующая массив-уменьшение.

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

const prefixSum = (arr) => {

  let result = [arr[0]]; // The first digit in the array don't change
  arr.reduce((accumulator, current) => {
       result.push(accumulator + current);

       return accumulator + current; // update accumulator
  });
  return result;
}

Ответ 13

/**
 * Turn an array of numbers to cumulative sum array
 * @param { Array } [1,2,3,4,5]
 * @return { Array } [1,3,6,10,15]
 */

const accumulate = (a, c) => a + c

const cusum = arr => arr.map((v, i, data) => {
    return data.slice(0, i + 1).reduce(accumulate)
})

Ответ 14

Возвращает отсортированные объекты по ключевым и отсортированным массивам!!!

var unsorted_obj = {
  "2016-07-01": 25,
  "2016-07-04": 55,
  "2016-07-05": 84,
  "2016-07-06": 122,
  "2016-07-03": 54,
  "2016-07-02": 43
};

var sort_obj = function(obj){
  var keys = [];
  var sorted_arr = [];
  var sorted_obj = {};

  for(var key in obj){
    if(obj.hasOwnProperty(key)){
      keys.push(key);
    }
  }

  keys.sort();

  jQuery.each(keys, function(i, key){
    sorted_obj[key] = obj[key];
    var val = obj[key];
    sorted_arr.push({
      idx: i,
      date: key,
      val: val
    })
  });

  return { sorted_obj: sorted_obj, sorted_arr: sorted_arr };

};

var sorted_obj = sort_obj(unsorted_obj).sorted_obj;
var sorted_arr = sort_obj(unsorted_obj).sorted_arr;

// sorted_arr = [{"idx":0,"date":"2016-07-01","val":25},{"idx":1,"date":"2016-07-02","val":43},{"idx":2,"date":"2016-07-03","val":54},...]
// sorted_obj = {"2016-07-01":25,"2016-07-02":43,"2016-07-03":54,...}

Ответ 15

Чтобы сохранить cumsum внутри функции до полной сборки, я предлагаю этот небольшой вариант на Matt Answer:

var cumsum = function(past_sums, new_value) {
  var last_sum = 1*past_sums.slice(-1);
  var new_sum = last_sum + new_value;
  return past_sums.concat([new_sum]);
}
var some_sums = [5, 10, 3, 2].reduce(cumsum, []);

Вот как это работает:

  • Первый цикл:
    • past_sums.slice(-1) === []
    • 1*past_sums.slice(-1) === 0
  • Все, кроме последнего цикла:
    • cumsum возвращает [ past_sums и new_sum] в следующем цикле past_sums
  • Последний цикл:
    • cumsum возвращает [5, 15, 18, 20] в качестве выходного массива some_sums

Его можно записать с меньшим количеством строк:

var cumsum = function(sums, val) {
  return sums.concat([ val + 1*sums.slice(-1) ]);
}
var some_sums = [5, 10, 3, 2].reduce(cumsum, []);

С функциями стрелок (Не для ≤IE11 или Opera Mini), я бы написал следующее:

var cumsum = (sums,val) => sums.concat([ val + 1*sums.slice(-1) ]);
var some_sums = [5, 10, 3, 2].reduce(cumsum, []);

Ответ 16

Используйте функцию стрелки вместо функции, вместо запятой вместо оператора, а currentIndex уменьшает обратный вызов.

[5, 10, 3, 2].reduce((r, a, i) => (r.push((i && r[i - 1] || 0) + a), r), []); // [ 5, 15, 18, 20 ]

Ответ 17

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

myarray.reduce((a, e, i) => {
  // a: Accumulator; e: current Element; i: current Index
  return a.length > 0 ? [...a, e + a[i - 1]] : [e];
}, []);

Карта, Фильтр, Уменьшить, Найти, Некоторые и т.д. сильно недооценены.