Вот функциональное программирование способ сделать это, используя промежуточный ES6 Map
:
const data = [[[{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}]], [[{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}],[{x: 1}, {y:2}, {z:3}]]];
const result = data[0].map( (arr, i) => Array.from(data.reduce( (acc, grp) => (
grp[i].forEach( o =>
Object.entries(o).forEach( ([k, v]) => acc.set(k, (acc.get(k) || 0) + v))
), acc
), new Map), ([k, v]) => ({ [k]: v })) );
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Пояснение
Чтобы облегчить объяснение, давайте договоримся о некоторых терминах:
У нас есть вход (массив), состоящий из групп .Каждая группа является массивом, состоящим из строк .Каждая строка состоит из объектов , каждый из которых имеет одну пару свойство / значение.
Выход не имеет группы level, но у него есть строки , снова состоящие из объектов , каждая из которых имеет одну пару свойство / значение.
Итак, используя эти термины, давайте пройдемся по коду:
Поскольку число строк в выходном массиве равно количеству строк в любой из групп, представляется хорошим началом сопоставить строки первой группы, например, как data[0].map
.
Для каждой строки в выводе нам нужно составить суммы, и reduce
- хорошая функция-кандидат для этой работы, поэтому мы вызываем data.reduce
.Для начального значения этого reduce
вызова я передал пустой Map
.Цель состоит в том, чтобы заполнить эту Карту парами ключ-сумма.Позже мы можем затем разложить эту Карту на отдельные объекты, каждый из которых имеет только одну из этих пар ключ / сумма (но это на потом).
Таким образом, reduce
начинается с Map
и повторяется погрупп.Нам нужно взять строку i th из каждой группы, чтобы найти объекты, которые нужно «добавить».Итак, мы берем строку grp[i]
.
Для каждого объекта в этой строке мы получаем имя свойства и значение с Object.entries(o)
.Фактически, эта функция возвращает массив, поэтому мы выполняем итерацию по ней с forEach
, зная, что на самом деле мы будем выполнять итерацию только один раз, поскольку на практике существует только одно свойство.Теперь у нас есть ключ (k
) и значение v
.Мы находимся на самом глубоком уровне в структуре ввода.Здесь мы настраиваем аккумулятор.
С помощью acc.get(k)
мы можем знать, что мы уже накопили для определенного ключа (например, для "x").Если у нас там еще ничего не было, он инициализируется с 0, выполняя || 0
.Затем мы добавляем к нему текущее значение v
и сохраняем эту сумму обратно на карту с acc.set(k, ....)
.Используя оператор запятой, мы возвращаем acc
обратно в реализацию reduce
(мы могли бы использовать return
здесь, но оператор запятой является более кратким).
И поэтому Map получает все суммы заключ.С Array.from
мы можем перебрать каждую из этих пар ключ / сумма и, используя аргумент обратного вызова, превратить эту пару в правильный маленький объект (с { [k]: v }
).Обозначение [k]
также является новшеством в ES6 - оно допускает динамические имена ключей в литералах объектов.
Итак ... Array.from
возвращает массив небольших объектов, каждый из которых имеет сумму.Этот массив представляет одну строку для вывода.Метод map
создает все строки, необходимые для вывода.