18

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!

3
  • 2
    You should post one of those numerous pieces of code. Commented May 22, 2013 at 11:46
  • 7
    We should vote more for this kind of good formatted and well explained questions! +1 Commented May 22, 2013 at 11:47
  • Your example would yield you four arrays as the difference between the first two dates in the second array is two days Commented May 22, 2013 at 12:04

5 Answers 5

4

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/

Sign up to request clarification or add additional context in comments.

4 Comments

Worked perfectly! I chose yours because it seemed very clean and simple. Thankyou very much.
@MichaelH You are welcome! I forgot to mention that array .reduce() may not be supported by ancient browsers, and MDN suggests to use a shim for compatibility (if you really need that).
Fortunately we only support modern browsers. Cheers.
Why array length is 4, ideally only three nested arrays should be created.
1

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

Comments

1

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/

Comments

1

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

Comments

1
// 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++;
    }

}

1 Comment

Unfortunately javascript doesn't have a peek method so we have to push the last element back on

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.