5

Let say we have a collection like this in Javascript:

[
    { date: 'Fri, 02 May 2014 19:05:00 GMT', value:'abc' },
    { date: 'Fri, 02 May 2014 23:43:00 GMT', value:'jkl' },
    { date: 'Fri, 02 May 2014 19:01:00 GMT', value:'def' },
    { date: 'Fri, 02 May 2014 19:09:00 GMT', value:'ghi' },
    { date: 'Fri, 02 May 2014 23:54:00 GMT', value:'mno' }
]

I would like to to find an elegant algorithm to group by this array by "closest" date. If a date is 15 minutes before or after a previous date, it will be pushed in the same object.

I doesn't really matter how the sub-array will be structured. The result for this entry could be:

[
    [
        { date: 'Fri, 02 May 2014 19:05:00 GMT', value:'abc' },
        { date: 'Fri, 02 May 2014 19:01:00 GMT', value:'def' },
        { date: 'Fri, 02 May 2014 19:09:00 GMT', value:'ghi' }
    ], [
        { date: 'Fri, 02 May 2014 23:43:00 GMT', value:'jkl' },
        { date: 'Fri, 02 May 2014 23:54:00 GMT', value:'mno' }
    ]
]

I have try without real success using underscore.js:

_.map(logs_by_date, function(group, date) {
    return _.reduce(group, function(memo, elem) {
        var moment = get_moment(elem);
        memo[moment].push(elem);
        return memo;
    }, { 'date': date});
});
10
  • I'm a fan of underscore for work like this. They have a groupBy function that should help. underscorejs.org/#groupBy Commented May 30, 2014 at 22:08
  • 1
    @StéphanLascar: When does time start? Is it every 15 minutes from the earliest time in the list, or 15 minutes from the top of the hour, or something different? Commented May 30, 2014 at 22:15
  • 1
    @StéphanLascar In that case, do you realize that the answer is not unique? Again, if you look at the dates 19:00:00, 19:10:00 and 19:20:00, how would you group them? Is the order in which the dates are provided relevant? Commented May 30, 2014 at 22:18
  • 1
    You should be able to figure this out with a little effort. Here's a really verbose example to get you started -> jsfiddle.net/PM3v9/1 Commented May 30, 2014 at 22:20
  • 1
    It's just an example of how to do this, which is why I didn't post it as an answer, it's not really clear to me what the sorting rules should be, but this will give you the result you wanted for that particular data, but what should happen if you have ten times with five minute intervals, should all of them end up in the same array or should some sort of initial time be used etc. It's all very unclear ! Commented May 30, 2014 at 22:27

2 Answers 2

7

Starting with the UnderscoreJS code from tjdett for a group-by-year question:

var dateGroups = _.chain(objarray)
                  .groupBy(function(obj) { return obj.date.getFullYear(); })
                  .sortBy(function(v, k) { return k; })
                  .value();

You could try this same solution with a groupBy function designed for 15 minute intervals instead of years, with return Math.floor(+(obj.date)/(1000*60*15)); This return statement uses + to convert the Date object to a number of milliseconds (since epoch), and then divides by 1000*60*15 for 15 minute intervals with Math.floor() discarding the fraction.

For that to work, obj.date must be type Date. If your dates are just strings, you may first need to parse the year, month, day, hour, minutes out of those strings and then construct a new Date object.

This will create absolute 15 minute clock blocks, i.e. 01:00:00-01:14:59.9999, 01:15:00-01:29:59.9999; not 15 minutes that begin with new activity.

So if you want a group of 15 minutes of data that starts with new data, the groupBy function would need to be created with a closure retaining state of when the current group ends so that new groups could be started, and it would need to be fed from objects sorted by date, so that a sort needs to happen first.

That sounds Rube-Goldbergish, and might be easier to do directly like this (untested):

fixDates(objArray); // a function you'll write to turn your date strings into Date objects
function compareDates(a,b){ return (+a.date)-(+b.date); }
objArray.sort(compareDates); // sorts in place, array is changed
var groups = [], g=[], d=0;
for (var gx=+objArray[0].date+15*60*1000,i=0,l=objArray.length; i<l; ++i){
    d = +(objArray[i].date);
    if (d>gx){ 
       groups.push(g);
       g = [];
       gx = +objArray[i].date+15*60*1000;
    }
    g.push(objArray[i]);
}
groups.push(g);  // include last group otherwise unpushed
// result in groups
Sign up to request clarification or add additional context in comments.

Comments

0

This method takes startDate,EndDate and interval to break DateTime and return DateTime Collection on specified interval

   const createDateTimeInterval = (startDate, endDate, interval) => {
        const dateArray = [];
        let currentDate = new Date(startDate);
        while (currentDate < new Date(endDate)) {
            var date = new Date(currentDate);
            let dateinString;
            if (date.getHours() < 12) {
                dateinString = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':' + (date.getMinutes() === 0 ? date.getMinutes() + '0' : date.getMinutes()) + ' AM';
            }
            else {
                dateinString = ((date.getHours() - 12) < 10 ? '0' + (date.getHours() - 12) : (date.getHours() - 12)) + ':' + (date.getMinutes() === 0 ? date.getMinutes() + '0' : date.getMinutes()) + ' PM';
            }
            dateArray.push({ label: dateinString, value: JSON.stringify(new Date(currentDate)) });
            currentDate = new Date(currentDate.getTime() + interval);
        }
    
        return dateArray;
    }
    const currentDate = new Date(new Date().getFullYear() + '-' + new Date().getMonth() + '-' + new Date().getDate())
    const nextDate = new Date(new Date(currentDate).getTime() + 60000 * 60 * 24)

This is the 15 minutes interval on a current date.

var dateOptions = createDateTimeInterval(currentDate, nextDate, (60000 * 15));

1 Comment

Please provide additional details in your answer. As it's currently written, it's hard to understand your solution.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.