Tarun Dugar
Tarun Dugar

Reputation: 8971

lodash: aggregating and reducing array of objects based on date

I am new to Lodash and Functional Programming concepts. So, I have an array of objects with day-wise date like these:

[
    {
         "date": '1-Jan-2015',
         "count": 4 
    },
    {
         "date": '4-Jan-2015',
         "count": 3 
    },
    {
         "date": '1-Feb-2015',
         "count": 4 
    },
    {
         "date": '18-Feb-2015',
         "count": 10 
    }
]

and I want to reduce and aggregate it in such a way that I get an array of objects where each object has monthly data instead of day-wise data like this:

[
    {
        "date": 'Jan, 2015',
        "count": 7 // aggregating the count of January
    },
    {
        "date": 'Feb, 2015',
        "count": 14 //aggregating the count of February
    }
]

Currently, I have a written a very unreadable and convoluted code full of ifs and fors which works. However, I want to refactor it using lodash. Is it possible using lodash? I looked around and found _.reduce and _.groupBy which I can probably use but I am stumped right now and can't figure out a good clean implementation.

Upvotes: 2

Views: 6054

Answers (2)

cl3m
cl3m

Reputation: 2801

You don't need lodash to achieve what you want, you could use plain old Javascript:

var array = [{
  "date": '1-Jan-2015',
  "count": 4
}, {
  "date": '4-Jan-2015',
  "count": 3
}, {
  "date": '1-Feb-2015',
  "count": 4
}, {
  "date": '18-Feb-2015',
  "count": 10
}]

var result = array.reduce(function(ar, item) {
  var index = item.date.split('-').slice(1,3).join(', ') //getting date Month-Year
  _item = ar.filter(function(a) { 
    return a.date === index
  })[0] // getting item if already present in array

  // getting index of _item if _item is already present in ar
  indexOf = ar.indexOf(_item) 

  if(indexOf > -1)
    // we sum the count of existing _item
    ar[indexOf] = {date: index, count: count: _item.count + item.count } 
  else
    // item is not yet in the array, we push a new _item
    ar.push({date: index, count: item.count}) 

  return ar; // return the array as required by reduce
}, []) // initialize the reduce method with an empty array

console.log(result) // your array with aggregated dates

And for the fun, a lodash version:

_.values(array.reduce(function(obj, item) {
  var index = item.date.split('-').slice(1, 3).join(', ')
  obj[index] = {date: index, count: (obj[index] && obj[index].count || 0) + item.count}
  return obj
}, {}))

See jsfiddle here

Upvotes: 5

Jagdish Idhate
Jagdish Idhate

Reputation: 7742

We can use _.reduce & _.values

var arr = [
    {
         "date": '1-Jan-2015',
         "count": 4 
    },
    {
         "date": '4-Jan-2015',
         "count": 3 
    },
    {
         "date": '1-Feb-2015',
         "count": 4 
    },
    {
         "date": '18-Feb-2015',
         "count": 10 
    }
]

_.values(_.reduce(arr,function(result,obj){
  var name = obj.date.split('-');
  name = name[1]+', '+name[2];  
  result[name] = {
    date:name,
    count:obj.count + (result[name]?result[name].count:0)
  };
  return result;
},{}));

Upvotes: 6

Related Questions