MichaelH
MichaelH

Reputation: 1620

Javascript Get Sequential Dates in Array

I have an array with the following values (example):

   [
      1367848800000: true,
      1367935200000: true,
      1368021600000: true,
      1368108000000: true,
      1368194400000: true,
      1368367200000: true,
      1368540000000: true,
      1368626400000: true,
      1368712800000: true
    ]

Where the index is a date time. The date time will always be at 12:00:00 on a date.

In this example, the first five dates are consecutive, then one day by itself, and then another group of 3 dates. An example of what I mean is below.

Dates on Calendar

Now, what I am trying to do is find sequential dates and put them into an array as follows:

   [
      1367848800000,
      1367935200000,
      1368021600000,
      1368108000000,
      1368194400000
   ],
   [
      1368367200000,
      1368540000000,
      1368626400000,
   ],
   [
      1368712800000Ω
   ]

So in the end, I have an array, with 3 arrays of all the times. I have tried numerous pieces of code, but everything bugs out and nothing is worth posting on here. Any help would be much appreciated!

Upvotes: 18

Views: 3597

Answers (5)

ose
ose

Reputation: 4085

// Preconditions: singleArray contains the input array with each element corresponding to a time index. singleArray is sorted.

var outputArray = new Array();
var stack = new Array();
var stackSize = 0;

var i;
for( i = 0; i < singleArray.length; i++ )
{
    // Get the last element on the stack
    var lastElement = (stackSize == 0) ? 0 : stack.pop();

    // Compare to see if difference is one day
    if( singleArray[i] - lastElement == 86400000 ) // 24 * 60 * 60 * 1000
    {
        // Dates are 1 day apart
        if( lastElement != 0 ) stack.push(lastElement);
        stack.push(singleArray[i]);
        stackSize++;
    }
    else
    {
        if( lastElement != 0 ) stack.push(lastElement);

        var tempQueue = new Array();
        while(stackSize > 0)
        {
            // Build up a new array containing consecutive days
            // using a queue
            tempQueue.push(stack.pop());
            stackSize--;
        }

        // Push the consecutive days onto the next place in the output array.
        outputArray.push(tempQueue);

        // Start a new group of consecutive dates
        stack.push(singleArray[i]);
        stackSize++;
    }

}

Upvotes: 1

rab
rab

Reputation: 4144

tried array sort with forEach

var dates = [1367848800000, 1367935200000, 1368021600000,
           1368108000000, 1368194400000, 1368367200000,
           1368540000000, 1368626400000, 1368712800000];

var k = 0 , sorted = [[]];   

dates.sort( function ( a, b ){

    return +a > +b ? 1 : +a == +b ? 0: -1;
})
.forEach( function( v , i ){

    var a = v,b = dates[i+1]||0;

    sorted[k].push( +a );

    if ( (+b - +a) > 86400000) {
            sorted[++k] = []
    }
});

Later you can sort them per counts

sorted.sort( function ( a,b ){
    return a.length > b.length ? -1: 1;
});

The sorted array contains desired result jsfiddle

Upvotes: 1

Tomi Lammi
Tomi Lammi

Reputation: 2126

Gotta love these puzzles. Nice answers everyone, here's mine more jQueryish approach.

var datearray =  {
    1367848800000: true,
    1367935200000: true,
    1368021600000: true,
    1368108000000: true,
    1368194400000: true,
    1368367200000: true,
    1368540000000: true,
    1368626400000: true,
    1368712800000: true
};

$(function() {

    var result = dateSequences(datearray);
}

function dateSequences(array) {
    // parse json object to array of keys
    var keys = Object.keys(array);
    // sort it up
    keys = keys.sort();
    // convert them to dates
    var dates = new Array();
    $.each(keys, function(i) {
        dates.push(new Date(parseInt(keys[i])));
    });

    // now we have array of dates, search for sequential dates
    var final = new Array();
    var prevdate = undefined;
    var currentseq = 0;    
    $.each(dates, function(i, d) {
        // undefined?
        // first sequence
        if (prevdate == undefined) {
            final.push(new Array());
            final[currentseq].push(d);
        }
        else {
            // compare if difference to current date in loop is greater than a day
            var comp=new Date();
            comp.setDate(prevdate.getDate()+2);
            // Advance sequence if it is
            if (comp < d) {
                currentseq++;
                final[currentseq] = new Array();
            }
            // Push the date to current sequence
            final[currentseq].push(d);            
        }
        // store previous
        prevdate = d;
    });   

    return final;
}

Fiddle:

http://jsfiddle.net/f57Ah/1/

Upvotes: 1

Moritz Roessler
Moritz Roessler

Reputation: 8651

Sth like this could do:

  function sequentialize(dArr) {
      dArr = Object.keys(dArr).slice().sort();
      var last;
      var arrs = [[]];

      for (var i = 0, l = dArr.length; i < l; i++) {
          var cur = new Date();
          cur.setTime(dArr[i]);
          last = last || cur;

          if (isNewSequence(cur, last)) {
              arrs.push([]);
          }

          arrs[arrs.length - 1].push(cur.getTime()); //always push to the last index
          last = cur;
      }


      return arrs;


      function isNewSequence(a, b) {
          if (a.getTime() - b.getTime() > (24 * 60 * 60 * 1000))
              return true;
          return false;
      }
  }

Now if you pass your example Array/Object to the sequentialize function

  var dates = {
      1367848800000: true,
      1367935200000: true,
      1368021600000: true,
      1368108000000: true,
      1368194400000: true,
      1368367200000: true,
      1368540000000: true,
      1368626400000: true,
      1368712800000: true
  };

  console.log(sequentialize(dates));

This gives the following output

  [
      [
          1367848800000,
          1367935200000,
          1368021600000,
          1368108000000,
          1368194400000
      ],
      [
          1368367200000
      ],
      [
          1368540000000,
          1368626400000,
          1368712800000
      ]
  ]

This simply

  1. creates an array out of the Date keys,

  2. Sorts them

  3. Iterates over them

  4. If the difference of the Current and Last Date is greate than a day

  5. Push a new Array to the Sequence Array

  6. Push the Current Date to the last Array in the Sequence Array

    Demo on JSBin

Note: You may have to change the isNewSequence function to actually fit your needs

Upvotes: 1

VisioN
VisioN

Reputation: 145478

The following approach uses array .reduce() method:

var arr = [1367848800000, 1367935200000, 1368021600000,
           1368108000000, 1368194400000, 1368367200000,
           1368540000000, 1368626400000, 1368712800000],
    i = 0,
    result = arr.reduce(function(stack, b) {
        var cur = stack[i],
            a = cur ? cur[cur.length-1] : 0;

        if (b - a > 86400000) {
            i++;
        }

        if (!stack[i])
            stack[i] = [];

        stack[i].push(b);

        return stack;
    }, []);

console.log(result);

DEMO: http://jsfiddle.net/gbC8B/1/

Upvotes: 4

Related Questions