'Sum of two multi dimensional array

I have a array in JavaScript like this.

var arr=
[ 
  ['A'],[1,2,3,4],
  ['A'],[4,3,2,1],
  ['B'],[10,12,3,1],
  ['B'],[1,2,3,4],
  .
  .
  .
  .
  ['AZ'],[1,2,3,4]
]

and I want the output to summarize the array like -

var output=
[
  ['A'],[5,5,5,5],
  ['B'],[11,14,6,5],
  ['AZ'],[1,2,3,4]
]

Thanks.



Solution 1:[1]

Script

You can use the following script to achieve what you want to do.

const arr = [
  ["A"],
  [1, 2, 3, 4],
  ["A"],
  [4, 3, 2, 1],
  ["B"],
  [10, 12, 3, 1],
  ["B"],
  [1, 2, 3, 4],
  ["AZ"],
  [1, 2, 3, 4],
];

/**
 * Generator to return key-value pairs with array[i] being the key and array[i+1] being the value
 * @param {Array<any>} array
 */
function* keyValue(array) {
  // make sure we can build pairs (other ways of handling this are also possible)
  if (array.length % 2 !== 0)
    throw new RangeError(
      "Array length must be dividable by 2 without remainder!"
    );
  for (let i = 0; i < array.length; i += 2) {
    yield [array[i], array[i + 1]];
  }
}

// here the created key-value pairs
console.log("Key-value pairs created by keyValue() generator function:");
console.log([...keyValue(arr)]);

// loop over key value pairs and sum up all the individul arrays based on the letter assigned to them
const result = [...keyValue(arr)].reduce((all, [[key], array]) => {
  // if we don't have values for this letter, assing copy of the array to that letter
  if (!all[key]) all[key] = [...array];
  // we have some values for that letter already, sum up each value
  else all[key] = all[key].map((prev, idx) => prev + array[idx]);
  return all;
}, {});
// this would be a "better" result to my mind as there is no point wrapping single string values in arrays
// When using objects the values can easily be accessed in O(1)
console.log(result);

// now transform JS object to array of arrays
console.log("Result:");
const transformed = Object.entries(result).flatMap(([key, value]) => [[key], value]);
console.log(transformed);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Please note: This implementation assumes that the arrays for a given letter have the same length (as is the case in your example).

Explanation

First of all, I use a generator function keyValue() to always group two consecutive values in the array (a key and a value) together. One could also do this differently but once you understand how generators work that's an easy and elegant approach, I think. For this demo I just throw an error if the array is not dividable by 2 without remainder, but one could also handle this more gracefully.

Then, using reduce(), I iterate over the array created by using keyValue() and for each element in the array I check if I've encountered that value before. If I have not, I create a copy of the array (for immutablility) and assign it to the key i.e. a letter. If I have encountered a certain letter before I add up the values that I have previously saved assigned to that letter with the ones I am currently processing. After iteration all sums are calculated and I have a JavaScript object containing the results.

To my mind, this would be a good output because your output is a bit odd, since there is no point storing single letters in an array or even arrays of arrays. Using a JavaScript object is much more convenient and faster for lookups.

Nevertheless, you can easily deduct your result from the created object using flatMap().

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1