2016-03-24 2 views
2

Учитывая многомерный массив:многомерных массив накопленной суммы в Javascript

var a = [[3,2,5], [4,1,7], [1,6,8]]; 

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

[[3,2,5], [7,3,12], [8,9,20]]; 
  • суммарная сумма по 1-му элементам каждой подматрицы: 3 4 1
  • сумма диплом по 2-му элементам каждой подматрицы: 2 1 6
  • суммарная сумма на 3-х элементах каждой подматрицы: 5 7 8

Я попытался использовать reduce(), но не могу получить ожидаемый результат.

Любые предложения, очень ценные.

S

ОБНОВЛЕНИЕ - Принимая его на следующий уровень:

var a = [ 
    [new Date(), 3,2,5], 
    [new Date(), null,1,7], 
    [new Date(), null,6,8], 
    [new Date(), 1,2,3] 
]; 

Если в результате:

[[new Date(), 3,2,5], 
[new Date(), null,3,12], 
[new Date(), null,9,20], 
[new Date(), 4,11,23]] 

Мой подход заключается в создании многомерного offsetIndex массива :

var offsetIdx = []; 
     for (var i=1; i<a.length; i++) { 

      for (var z=0; z<a[i].length; z++) { 
       var zValue = a[i][z]; 

       oIdx = offsetIdx[z] || 0; 

       a[i][z] = zValue && z!==0 ? a[i-1-oIdx][z] + zValue : zValue; 

       if(!zValue){ 
        offsetIdx[z] = oIdx + 1; 
       } else { 
        offsetIdx[z] = 0; 
       } 
      } 
     } 

Рад видеть другие подходы и способы сделать его сверхлегким.

+0

Как это, что ваш выходной массив может иметь такое же количество элементов, при условии, что сумма будет применяться к вход? –

+0

@NewAlexandria: он накапливает результат, когда он идет в каждый массив, поэтому первый массив не изменяется, второй - это сумма самого первого плюса (для каждого члена соответственно), третья - сумма результата второго, снова плюс его собственные соответствующие члены и т. д. –

+0

Правильно. Я наклонился к функции reduce(), когда он передает ссылку на предыдущий элемент. Я видел примеры с плоскими 1 тусклыми массивами, но не могу его адаптировать, чтобы разместить многомерный массив. – Seb

ответ

3
for (var i=1; i<a.length; i++) { 
    for (var z=0; z<a[i].length; z++) { 
    a[i][z] = a[i-1]][z] + a[i][z] 
    } 
} 

Массив должен динамически обновляться по мере продолжения цикла. Это разрушительно, поэтому он изменит исходный массив.

+0

Спасибо, ребята, все жизнеспособные решения. Мне нравится подход @char, поскольку он легкий, использует vanilla JS и сверхбыстрый. Хороший. – Seb

+0

Спасибо за комментарий Seb. Мне сказал мой работодатель, когда я решил использовать библиотеки или методы non loop, поскольку они замедляют работу. – char

+0

@char обучить вашего работодателя тому, как более удобный код и меньшее количество ошибок более важны, чем неизмеренное увеличение скорости :) – djechlin

0

Это даст вам сумму по всем элементам. Не совсем то, что вы просите, но я оставлю этот ответ здесь для будущих посетителей, которые поймут заголовок вопроса.

  1. Flatten first using your favorite library (подчеркивания и lodash оба имеют его)
  2. Затем уменьшить сумму +.

    _.flatten([1, [2, [3, [4]], 5]]); 
    // → [1, 2, [3, [4]], 5] 
    
3

function cumulativeSum(arr) { 
 
    var result = [arr[0]]; 
 
    for(var i = 1; i < arr.length; i++) { 
 
     result.push([]); 
 
     for(var j = 0; j < arr[0].length; j++) { 
 
      result[i].push(result[i - 1][j] + arr[i][j]); 
 
     } 
 
    } 
 
    return result; 
 
} 
 
    
 
document.body.innerHTML = JSON.stringify(cumulativeSum(
 
    [[3,2,5], [4,1,7], [1,6,8]] 
 
))

В отличие от других ответов, это один не разрушительный, сохраняя исходный массив и возвращает результат.

+0

Это не будет работать, поскольку предыдущий результат не будет обновляться. Например, когда вы дойдете до третьего массива, второй массив еще не был обновлен, чтобы включить первую сумму массивов, поэтому вы получите только значения 2-го массива + 3-го массива вместо значений 1-го и 2-го и 3-го массивов. – char

+1

@char: Он работает, потому что он берет предыдущие значения из результата, а не оригинала. –

+1

@char https://jsfiddle.net/hojwxane/ Это действительно работает. Причина в том, что массив результатов хранит исходную сумму совокупности, а следующий элемент устанавливается как сумма предыдущего элемента массива результатов и следующего элемента исходного массива. – afuous

0

Какой матовый вопрос.

Почему бы не перенести массив сначала? Ответ на этот вопрос - Transposing a 2D-array in JavaScript - предлагает underscore.js решение:

_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]]) 

, чтобы сделать это. Есть много способов.

Тогда сумма должна быть намного проще - всего .map(f), где f - ваша сумма на одну функцию массива.

IMO это хорошее и удобочитаемое решение, потому что «транспонирование + сумма» очень верна для характера столбцовой суммы вопроса, и я бы избегал решения, требующего серьезного решения, которое скрывает это.

+1

@ RokoC.Buljan сделано – djechlin

1

Использование Array.reduce, это будет выглядеть следующим образом

var arr = [[3,2,5], [4,1,7], [1,6,8]]; 
 

 
var arr2 = arr.reduce(function(a,b) { 
 
    var nested = Array.isArray(a[0]); 
 
    b = b.map(function(x,i) { 
 
    \t return x + (nested ? a[a.length-1] : a)[i]; 
 
    }); 
 
    if (nested) a.push(b); 
 
    return nested ? a : [a,b]; 
 
}); 
 

 
document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';

Вот такой sligthly "оптимизированный" (golfed) версии, проходящий в качестве отправной точки для сокращения и нарезка массива

var arr = [[3,2,5], [4,1,7], [1,6,8]]; 
 

 
var arr2 = arr.slice(1).reduce(function(a,b) { 
 
\t return [a.push(b.map(function(x,i) {return x+a[a.length-1][i]})), a].pop(); 
 
},[arr[0]]); 
 

 
document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';

делая это один вкладыш с использованием ES2015

var arr = [[3,2,5], [4,1,7], [1,6,8]]; 
 
var a2 = arr.slice(1).reduce((a,b)=>[a,a.push(b.map((x,i)=>x+a[a.length-1][i]))][0],[arr[0]]); 
 

 
document.body.innerHTML = '<pre>' + JSON.stringify(a2, 0, 4) + '</pre>';

Смежные вопросы