2017-02-15 12 views
0

У меня есть следующий код, который работает просто отлично. Мне просто интересно, есть ли более элегантный/оптимизированный способ сделать это.JavaScript 2D-массив группировки: есть ли более элегантный/оптимизированный способ?

Long «код» Короче говоря, учитывая данные:

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], 
]; 

Скажите, что я хочу, чтобы сгруппировать по индексу 1 столбца и только индексами столбцов суммы 2, 3, 5.

Ожидаемый результат:

[ 
    ["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));

К сожалению, я не могу использовать ES6 на этом ...

Спасибо!

ответ

0

Я попытался найти решение для вашего вопроса. Было бы много хороших функций ES6, которые сделали бы решение более читаемым/чистым. Но здесь это решение без каких-либо признаков ES6:

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]); 
    }); 
} 

Объяснение:

  • Объект со свойствами 'A', 'B' и 'C' будет создана.
  • Массив [0, 0, 0] будет присвоен каждому свойству.
  • Loop myArray и colsToSum и добавить значения в свойства объекта правой
  • Преобразование объекта в массив и вернуть его

Может быть, есть более эффективные решения :)