У меня есть следующий массив:

var objArray = [
    { num: 1, date: '1/12/2017' },
    { num: 3, date: '1/12/2017' },
    { num: 7, date: '1/12/2017' },
    { num: 1, date: '1/13/2018' },
    { num: 3, date: '1/16/2018' },
    { num: 4, date: '1/16/2018' }
   ];

Я хочу объединить их с одинаковыми датами, чтобы выходной массив выглядел так:

var outputArr = [
    { num: 11, date: '1/12/2017' },
    { num: 1,  date: '1/13/2018' },
    { num: 7,  date: '1/16/2018' }
   ];

Я добавляю все num с похожими датами и создаю один новый объект.

У меня есть очень большой набор данных объектов, таких как этот, поэтому я пытаюсь уменьшить количество времени на обработку для этого.

Я отсортировал массивы по дате, чтобы они отражали objArray.

Циклы for кажутся громоздкими, поскольку я беру первую дату в массиве и проверяю каждый второй элемент массива в виде следующего псевдокода:

var newArr = [];
for(i = 0; i < objArray.length; i++) {
    for(j = 0; j < objArray.length; j++) {
        var tempArr = [];
        // check every date manually
        // add similar to new array
        tempArr.push({ similar items });
    }
    newArr.push(tempArr):
}

// Do another couple loops to combine those like arrays into another array    

Должен быть более элегантный способ сделать это, чем запуск нескольких циклов for.

Мы ценим любые предложения.

2
razorsyntax 20 Авг 2018 в 20:54

4 ответа

Лучший ответ

Просто используйте Array.reduce() для создания карты и группировки значений по дате, Object.values() на карте даст вам желаемое выходное значение:

let arr = [ { num: 1, date: '1/12/2017' }, { num: 3, date: '1/12/2017' }, { num: 7, date: '1/12/2017' }, { num: 1, date: '1/13/2018' }, { num: 3, date: '1/16/2018' }, { num: 4, date: '1/16/2018' } ];
   
let result = Object.values(arr.reduce((a, {num, date})=>{
  if(!a[date])
    a[date] = Object.assign({},{num, date});
   else
    a[date].num += num;
  return a;
 },{}));
 console.log(result);
4
amrender singh 20 Авг 2018 в 17:59

Вы также можете удалить операторы if и использовать Set, если хотите быть еще более декларативным.

var objArray = [
    { num: 1, date: '1/12/2017' },
    { num: 3, date: '1/12/2017' },
    { num: 7, date: '1/12/2017' },
    { num: 1, date: '1/13/2018' },
    { num: 3, date: '1/16/2018' },
    { num: 4, date: '1/16/2018' }
];
var mSet = new Set(objArray.map(d => d.date));
return Array.from(mSet).map(d => {
    return
    { 
        date: d,
        sum: (objArray
            .filter(o => o.date === d)
            .map(n => n.num)
            .reduce((a, c) => a + c, 0))
    }
);

Это возвращает:

[{ date: 1/12/2017, sum: 11},
{ date: 1/13/2018, sum: 1 },
{ date: 1/16/2018, sum: 7 }]
1
Erick 21 Авг 2018 в 19:01

Используя lodash,

// Aggregate num from unique dates
var g = _.groupBy(objArray,'date')
Object.keys(g).map(k=>({num:g[k].reduce((a,c)=>c.num+a,0),date:k})) 
2
Cody G 20 Авг 2018 в 18:09
var objArray = [
    { num: 1, date: '1/12/2017' },
    { num: 3, date: '1/12/2017' },
    { num: 7, date: '1/12/2017' },
    { num: 1, date: '1/13/2018' },
    { num: 3, date: '1/16/2018' },
    { num: 4, date: '1/16/2018' }
   ];

let outputArr = Array.from(objArray.reduce((acc, obj)=>{
  acc.set(obj.date, (acc.get([obj.date]) || 0) + obj.num);
  return acc;
}, new Map()))
.map(kv=>({num: kv[1], date: kv[0]}))

console.log(outputArr);

Дает:

[ { num: 11, date: '1/12/2017' },
  { num: 1, date: '1/13/2018' },
  { num: 7, date: '1/16/2018' } ]
1
Hero Qu 20 Авг 2018 в 18:44
51936130