thehme
thehme

Reputation: 2896

tallying similar properties on a javascript object

I have an array of objects like this:

[{"ts":"Thu, 20 Aug 2015 18:00:00 GMT"},
{"ts":"Thu, 20 Aug 2015 17:00:00 GMT"},
{"ts":"Thu, 20 Aug 2015 16:00:00 GMT"},
{"ts":"Thu, 20 Aug 2015 15:00:00 GMT"},
{"ts":"Wed, 19 Aug 2015 16:00:00 GMT"},
{"ts":"Wed, 19 Aug 2015 15:00:00 GMT"}]

I am using something like this to traverse through each time:

_.each(times,function(t){
    console.log(t.ts);
}, this);

I am using moment to make sure that the dates all have the same end of day time, so as to ignore this variable. I would like to create a new object with a count of like times, e.g.

uniqueTimes = 
{
 {"Thu, 20 Aug 2015": 4},
 {"Wed, 19 Aug 2015": 2}
}

Any suggestions on how to do this? I was thinking of traversing the uniqueTimes object within the _.each function, but I have hundreds of times, so on each iteration uniqueTimes will be larger and larger. This doesn't seem efficient.

Upvotes: 3

Views: 101

Answers (3)

Ahmad Mageed
Ahmad Mageed

Reputation: 96557

Based on your usage of _.each it seems that you're using either LoDash or Underscore. In that case, both libraries have a handy _.countBy method (LoDash docs, Underscore docs) that would allow you to get your desired results as shown below.

Instead of the whole split/join approach I'm using, you could also use the regex approach that adeneo shared.

var times = [{"ts":"Thu, 20 Aug 2015 18:00:00 GMT"},
{"ts":"Thu, 20 Aug 2015 17:00:00 GMT"},
{"ts":"Thu, 20 Aug 2015 16:00:00 GMT"},
{"ts":"Thu, 20 Aug 2015 15:00:00 GMT"},
{"ts":"Wed, 19 Aug 2015 16:00:00 GMT"},
{"ts":"Wed, 19 Aug 2015 15:00:00 GMT"}];

var groupedCounts = _.countBy(times, function(item) {
  var split = item.ts.split(' ');
  var value = split.slice(0, split.length - 2).join(' ');
  return value;
});

document.body.innerHTML = '<pre>' + JSON.stringify(groupedCounts, null, 2) + '</pre>';
<script src="https://cdn.rawgit.com/lodash/lodash/3.0.1/lodash.min.js"></script>

Upvotes: 2

madox2
madox2

Reputation: 51931

With ES6 you can use Map() data structure for your task:

const result = data.reduce((m, i) => {
    const key = i.ts; // or format your date with moment
    return m.set(key, m.has(key) ? m.get(key) + 1 : 1);
}, new Map());

console.log(result);

Notice: check for Map compability in your environment.

Upvotes: 1

adeneo
adeneo

Reputation: 318372

You can just iterate and add to the unique times as you go

var times = [
    {"ts":"Thu, 20 Aug 2015 18:00:00 GMT"},
    {"ts":"Thu, 20 Aug 2015 17:00:00 GMT"},
    {"ts":"Thu, 20 Aug 2015 16:00:00 GMT"},
    {"ts":"Thu, 20 Aug 2015 15:00:00 GMT"},
    {"ts":"Wed, 19 Aug 2015 16:00:00 GMT"},
    {"ts":"Wed, 19 Aug 2015 15:00:00 GMT"}
];

var uniqueTimes = {};

times.forEach(function(time) {
    var t = (time.ts.match(/^(.*?)\s\d+\:/) || [])[1];
    
    t in uniqueTimes ? uniqueTimes[t]++ : uniqueTimes[t] = 1;
});

document.body.innerHTML = '<pre>' + JSON.stringify(uniqueTimes, null, 4) + '</pre>';

Upvotes: 1

Related Questions