0

I have the following code which works just fine. I'm just wondering if there's a more elegant/optimized way of doing so.

Long "code" short, given the data:

var myArray = [
  ['X', 'A', 0, 1, 'Y', 3],
  ['X', 'A', 4, 5, 'Y', 6],
  ['X', 'B', 6, 5, 'Y', 4],
  ['X', 'B', 3, 2, 'Y', 1],
  ['X', 'C', 7, 8, 'Y', 9],
];

Say I want to group by column index 1 and only sum column indexes 2, 3, 5.

Expected result is:

[
  ["A", 4, 6, 9],
  ["B", 9, 7, 5],
  ["C", 7, 8, 9]
]

// data
var myArray = [
  ['X', 'A', 0, 1, 'Y', 3],
  ['X', 'A', 4, 5, 'Y', 6],
  ['X', 'B', 6, 5, 'Y', 4],
  ['X', 'B', 3, 2, 'Y', 1],
  ['X', 'C', 7, 8, 'Y', 9],
];

// col that I want to group by
var colIndex = 1;

// cols I want to sum
var colsToSum = [2, 3, 5];

var arrayGroupBy = function(myArray, colIndex, colsToSum) {

  // get unique column values
  var uniqueValues = [];
  myArray.forEach(function(row) {
    if (uniqueValues.indexOf(row[colIndex]) === -1) {
      uniqueValues.push(row[colIndex]);
    }
  });

  var newData = [];
  uniqueValues.forEach(function(value) {

    // get filtered rows
    var filteredRows = myArray.filter(function(row) {
      return row[colIndex] === value;
    });

    var row = [value];

    // columns to sum
    colsToSum.forEach(function(num) {
      if (filteredRows.length === 1) {

        // push single row
        row.push(filteredRows[0][num]);

      } else {

        // sum row cols
        var total = filteredRows.reduce(function(sum, current) {
          return sum + current[num];
        }, 0);

        row.push(total);
      }

    });

    newData.push(row);
  });

  return newData;
};

console.log(arrayGroupBy(myArray, colIndex, colsToSum));

Unfortunately I can't use ES6 on this one...

Thanks!

1 Answer 1

1

I tried to find a solution for your question. There would be many good ES6 features which would make the solution a bit more readable/cleaner. But here is a solution without any ES6 features:

var groupBy = function(myArray, colIndex, colsToSum) {
  var obj = {};
  myArray.forEach(function(e) {
    if(!obj.hasOwnProperty(e)) {
      obj[e[colIndex]] = new Array(colsToSum.length + 1)
        .join('0').split('').map(parseFloat);
      }
  });

  myArray.forEach(function(row) {
    for (var i = 0; i < colsToSum.length; i++) {
      obj[row[colIndex]][i] += row[colsToSum[i]];
    }
  });

  return Object.keys(obj).map(function(key) {
    return [key].concat(obj[key]);
  });
}

Explanation:

  • An object with the properties 'A', 'B' and 'C' will be created.
  • An array [0, 0, 0] will be assigned to each property.
  • Loop myArray and colsToSum and add the values to the right object property
  • Convert the object to an array and return it

Maybe there are better solutions :)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.