Javascript group objects by property [closed]

I'm trying to group objects in an array by date:

var list = [
     {
         date: "2017-01-01",
         type: "type1",
         amount: 100
     },
     {
         date: "2017-01-01",
         type: "type2",
         amount: 150
     },
     {
         date: "2017-01-02",
         type: "type1",
         amount: 200
     }
]

And I'm trying to get something like:

var dateArr = [
   {
      date: "2017-01-01",
      activities: [
        {
           type: "type1",
           amount: 100
        },
        {
           type: "type2",
           amount: 150
        }]
   }
]

I have tried a few things...like this using underscore (from here https://stackoverflow.com/a/15888912/4989305):

var dateArr = _
.chain(list)
.groupBy('date')
.map(function(value, key) {
    return {
        date: key,
        activities: [{
            type: _.pluck(value, 'type'),
            amount: _.pluck(value, 'amount')
        }]
    }
})
.value();

I've also tried this (from here https://stackoverflow.com/a/31373860/4989305)

var dateArr = {};
list.forEach(function(item){
    dateArr[item.date] = dateArr[item.date]||[];
    dateArr[item.date].push(item);
});

But, for some reason both return empty.

Any help will be greatly appreciated.


A few lines of modern JavaScript will get you the result you want:

var dateArr = Object.values(list.reduce((result, {
    date,
    type,
    amount
}) => {
    // Create new group
    if (!result[date]) result[date] = {
        date,
        activities: []
    };
    // Append to group
    result[date].activities.push({
        type,
        amount
    });
    return result;
}, {}));

Explaination:

  1. Use Array.reduce to consolidate the list into a set of results, a plain object, grouped by date.
  2. The consolidate function destructure the item into three parameters.
  3. It then creates a new group if necessary.
  4. Current item's type and amount is then pushed to the group as part of an object literal.
  5. The same set is returned to the reduce, so that the next item will consolidate into the same set.
  6. Use Object.values to extract the values from the set. (Drop the keys)

You could use a hash table for groupiung by date and assign the single group to the result array.

var list = [{ date: "2017-01-01", type: "type1", amount: 100 }, { date: "2017-01-01", type: "type2", amount: 150 }, { date: "2017-01-02", type: "type1", amount: 200 }],
    result = [];

list.forEach(function (hash) {
    return function (a) {
        if (!hash[a.date]) {
            hash[a.date] = { date: a.date, activities: []};
            result.push(hash[a.date]);
        }
        hash[a.date].activities.push({ type: a.type, amount: a.amount });
    };
}(Object.create(null)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I hope this is what you exactly need.

var list = [
     {
         date: "2017-01-01",
         type: "type1",
         amount: 100
     },
     {
         date: "2017-01-01",
         type: "type2",
         amount: 150
     },
     {
         date: "2017-01-02",
         type: "type1",
         amount: 200
     }
]
var dateArrKeyHolder = [];
var dateArr = [];
list.forEach(function(item){
    dateArrKeyHolder[item.date] = dateArrKeyHolder[item.date]||{};
    var obj = dateArrKeyHolder[item.date];
    if(Object.keys(obj).length == 0)
    dateArr.push(obj);
    
    obj.date = item.date;
    obj.activities  = obj.activities || [];
    
    obj.activities.push({type:item.type, amount: item.amount });
});


console.log(JSON.stringify(dateArr));