I have the following json file
[{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},
{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},
{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},
{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}]
I want to add new items using JavaScript, jquery, to end up with
[{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},
{"id":5,"num":"n61","mov_date":"2019-02-02T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-03T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-04T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},
{"id":5,"num":"n61","mov_date":"2019-02-06T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-07T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},
{"id":5,"num":"n61","mov_date":"2019-02-09T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-10T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}]
maybe by calculating the number of missed items between dates, or just calculating the diff between the numbers represents the day i.e: "2019-02-01T00:00:00" and "2019-02-05T00:00:00" then add 3 items?
var items = [
{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},
{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},
{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},
{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}
]
var newItems = []
for(var i = 0; i < items.length; i++){
newItems.push(items[i])
var currentDay = moment(items[i].mov_date)
var nextDay = currentDay.add(1, 'days');
if(typeof items[i+1] !== 'undefined'){
var diff = moment(items[i+1].mov_date).diff(currentDay, 'days')
for(var j = 1; j <= diff; j++){
var newItem = JSON.parse(JSON.stringify(items[i]))
newItem.mov_date = moment(items[i].mov_date).add(j, 'days').utc(false).format();
newItem.orders = 0
newItems.push(newItem)
}
}
}
console.log(newItems)
<script src="https://cdn.jsdelivr.net/momentjs/2.13.0/moment.min.js"></script>
Check also this one that uses reduce() preserving all the props(including id) and only resetting orders and setting correct mov_date in between.
var items = [{
"id": 5,
"num": "n61",
"mov_date": "2019-02-01T00:00:00",
"orders": 19
},
{
"id": 5,
"num": "n61",
"mov_date": "2019-02-05T00:00:00",
"orders": 12
},
{
"id": 5,
"num": "n61",
"mov_date": "2019-02-08T00:00:00",
"orders": 5
},
{
"id": 5,
"num": "n61",
"mov_date": "2019-02-11T00:00:00",
"orders": 7
}
]
const newItems = items.reduce((acc, next) => {
// first run with early return
if (!acc.length) {
return [...acc, next]
}
// taking the recent item, to preserve the id and other props
const prevItem = acc[acc.length - 1];
// getting diff in days - 1
const days = moment.utc(next.mov_date).diff(moment.utc(prevItem.mov_date), 'days') - 1;
// [...Array] is a trick to get mappable arrays without array holes,
// but with initialized undefined values,
// so we can get the index during map
const inBetweenValues = [...Array(days)].map((_, dayIndex) => {
return {
...prevItem,
orders: 0,
mov_date: moment.utc(prevItem.mov_date).add(dayIndex + 1, 'days').format()
};
});
// merging it all, and moving to the next loop
return [...acc, ...inBetweenValues, next];
}, [])
console.log(newItems);
<script src="https://cdn.jsdelivr.net/momentjs/2.13.0/moment.min.js"></script>
You could use a Date object which you increment using its setDate method, and which you render to string with toJSON. Then when the date string matches the next entry, you copy it, otherwise you duplicate it with orders: 0:
const data = [{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}];
const end = new Date(data[data.length-1].mov_date + "Z");
const result = [];
for (let dt = new Date(data[0].mov_date+"Z"), i = 0; dt <= end; dt.setUTCDate(dt.getUTCDate()+1)) {
result.push({...data[i], ...(dt.toJSON().slice(0,19) === data[i].mov_date ? (i++, {}) : { orders: 0 })});
}
console.log(result);
Here is an algorithm that will do That for you. I used
Convert JS date time to MySQL datetime for date conversion.
function twoDigits(d) {
if(0 <= d && d < 10) return "0" + d.toString();
if(-10 < d && d < 0) return "-0" + (-1*d).toString();
return d.toString();
}
function toMysqlFormat() {
return this.getUTCFullYear() + "-" + twoDigits(1 + this.getUTCMonth()) + "-" + twoDigits(this.getUTCDate()) + "T" + twoDigits(this.getUTCHours()) + ":" + twoDigits(this.getUTCMinutes()) + ":" + twoDigits(this.getUTCSeconds());
};
var prev = 0;
for( var x = 1; x < obj.length; x++ ){
if( !obj[x -1].mov_date ){
continue;
}
var tx = Date.parse( obj[x-1].mov_date );
var diff = ( Date.parse(obj[x].mov_date ) - tx ) / (1000*24*60*60);
for( var y = 1; y < diff; y++ ){
obj.splice( x - 1 + y,0, { "id" : 5, "num" : "n61", "mov_date" : toMysqlFormat.bind( new Date( tx + ( y*1000*24*60*60) ) )(), "orders" : 0} );
}
x += diff - 1;
}
for( var x = 0; x < obj.length; x++ ){
console.log( JSON.stringify( obj[x] ) );
}
/* Result :
/* {"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19} */
/* {"id":5,"num":"n61","mov_date":"2019-02-02T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-03T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-04T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12} */
/* {"id":5,"num":"n61","mov_date":"2019-02-06T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-07T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5} */
/* {"id":5,"num":"n61","mov_date":"2019-02-09T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-10T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7} */
*/
Related
I have an array contains dates (yyyy/mm/dd format):
["2019-02-05", "2019-02-06", "2019-02-07", "2019-02-08", "2019-02-09", "2019-02-10", "2019-07-05", "2019-07-06", "2019-07-07", "2019-07-08", "2019-07-09", "2019-07-10", "2019-12-05", "2019-12-06"]
I want to divide it to several smaller pieces. I want to get 2d array and each array inside 2d array should has dates without gaps. So if the difference between two dates is more than 1 I want to add next date to next array inside 2d array. I don't know how many 1d arrays I will need, it depends on input array.
I expect to return sth like this:
[
["2019-02-05", "2019-02-06", "2019-02-07", "2019-02-08", "2019-02-09", "2019-02-10"],
["2019-07-05", "2019-07-06", "2019-07-07", "2019-07-08", "2019-07-09", "2019-07-10"],
["2019-12-05", "2019-12-06"]
];
This is what I did already but it isn't work properly:
function divideIntoBlocks(variant){
var array = [],
start = new Date(variant[0]),
stop = new Date(variant[variant.length - 1]);
for(var i = start; i <= stop; i.setDate(i.getDate() + 1)){
if(start == new Date(variant[0])){
var newArray = [];
newArray.push(start);
}
else{
if(getDiffDays(start.getDate() - 1, start) == 1){
newArray.push(start);
}
else{
array.push(newArray);
newArray = [];
newArray.push(start)
}
}
}
console.log(array);
}
Please make sure that your array is already sorted before using the solution below.
Solution with numbers as an input:
const arr = [1, 3, 4, 6, 7, 8, 10, 11, 13];
const result = [];
if (arr.length > 0) {
result.push([arr[0]]);
for (let i = 1; i < arr.length; i++) {
if (arr[i] - arr[i - 1] > 1) {
result.push([arr[i]]);
} else {
result[result.length - 1].push(arr[i]);
}
}
}
console.log(result); // [ [ 1 ], [ 3, 4 ], [ 6, 7, 8 ], [ 10, 11 ], [ 13 ] ]
Solution with dates as an input:
const arr = [
"2019-02-05",
"2019-02-06",
"2019-02-07",
"2019-02-08",
"2019-02-09",
"2019-02-10",
"2019-07-05",
"2019-07-06",
"2019-07-07",
"2019-07-08",
"2019-07-09",
"2019-07-10",
"2019-12-05",
"2019-12-06"
];
const result = [];
if (arr.length > 0) {
result.push([arr[0]]);
for (let i = 1; i < arr.length; i++) {
if (diffDays(arr[i], arr[i - 1]) > 1) {
result.push([arr[i]]);
} else {
result[result.length - 1].push(arr[i]);
}
}
}
console.log(result);
function diffDays(dateStr1, dateStr2) {
const date1 = new Date(dateStr1);
const date2 = new Date(dateStr2);
const diffTime = Math.abs(date2.getTime() - date1.getTime());
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays;
}
You could group your dates based on the month, reduce the array to object of object, get values of the object as array and sort:
let groupKey = 0;
let a = ["2019-02-05", "2019-02-06", "2019-02-07", "2019-02-08", "2019-02-09", "2019-02-10", "2019-07-05", "2019-07-06", "2019-07-07", "2019-07-08", "2019-07-09", "2019-07-10", "2019-12-05", "2019-12-06"]
let finalArr = Object.values(a.reduce((r, o) => {
let m = o.split(('-'))[1];
(r[m]) ? r[m].data.push(o): r[m] = {
group: String(m),
data: [o]
};
return r;
}, {})).sort((l, t) => l.group > t.group ? 1 : -1).map(u => u.data.sort((l, t) => new Date(l) > new Date(t) ? 1 : -1));
console.log(finalArr);
Making akobbs answer work with dates:
function nextdate (a) {
const r = [];
if (a.length > 0) {
r.push([a[0]]);
for (let i = 1; i < a.length; i++) {
if (Math.abs(new Date(a[i]) - new Date(a[i - 1])) / 864e+5 > 1) r.push([a[i]]);
else r[r.length - 1].push(a[i]);
}
}
return r;
}
Does this help ?
//step 0 init
const DAY = 86400000;
//step 1 - fetch
let arrDates = ["2019-02-05", "2019-02-06", "2019-02-07", "2019-02-08", "2019-02-09", "2019-02-10", "2019-07-05", "2019-07-06", "2019-07-07", "2019-07-08", "2019-07-09", "2019-07-10", "2019-12-05", "2019-12-06", "IDIOT DATE"];
//setp 2 - map to date objects
arrDates = arrDates.map((item) => {
return new Date(item);
});
//step 3 - filter for not wanted results
arrDates = arrDates.filter(e => e instanceof Date && !isNaN(e));
//step 4 sort
arrDates = arrDates.sort((a, b) => {
return a - b
});
//step 5 reducing it to 3d array
arrDates = arrDates.reduce((acc, cur) => {
//defines previousResult by looking up the accumulator
let previousResult = acc[acc.length - 1][acc[acc.length - 1].length - 1]
//check if dates difference exactly 86400000 Milliseconds AKA DAY
if (cur.getTime() - previousResult.getTime() === DAY) {
//true :: push to latest array in the accumulator
acc[acc.length - 1].push(cur)
} else {
//false push new array with value to the accumulator
acc.push([cur])
}
//returns accumulator back so it can be used every time
return acc;
},
//initial value Array.reduce( callback.fn , initial value )
// we take out the first value and init the stuff
[
[arrDates.shift()]
]);
console.log(arrDates);
I am trying to loop through an array of arrays with object [[{},{},{}],[{},{},{}]], and create a new array that basically "totals" the arrays. I am a bit at a loss on how to achieve this.
My data looks like this:
[
[{
"2017-01-05": 607
}, {
"2017-01-06": 430
}, {
"2017-01-07": 357
}, {
"2017-01-08": 277
}],
[{
"2017-01-09": 607
}, {
"2017-01-10": 430
}, {
"2017-01-11": 357
}, {
"2017-01-12": 277
}]
],
I would like to "count" and "label" each week, and total each week. Example:
newArray: [{"Week 1": 1075}, {"Week 2": 1590}]
I know I should probably use a forEach loop, but then it gets a bit sketchy:
dateArray.forEach( function (arrayWeek)
{
// push and name etc. functionality
});
I would greatly appreciate your assistance and guidance.
I would use the map function and reduce each week inside the map:
var days = [
[{"2017-01-05":607}, {"2017-01-06":430}, {"2017-01-07":357}, {"2017-01-08":277}],
[{"2017-01-09":607}, {"2017-01-10":430}, {"2017-01-11":357}, {"2017-01-12":277}]
];
function aggregator(memo, day) {
for (var i in day) {
memo += day[i];
}
return memo;
}
// Original version from the question
var weeks = days.map(function(week, index) {
var obj = {};
obj['Week ' + (index + 1)] = week.reduce(aggregator, 0);
return obj;
});
console.log(weeks);
// Follow up version from question in the comments
var weeks2 = days.map(function(week, index) {
return {
name: 'week ' + (index + 1),
total: week.reduce(aggregator, 0)
};
});
console.log(weeks2);
You can try something like this.
var data=[[{"2017-01-05":607},{"2017-01-06":430},{"2017-01-07":357},{"2017-01-08":277}],[{"2017-01-09":407},{"2017-01-10":430},{"2017-01-11":357},{"2017-01-12":277}]];
var result = data.reduce(function(p, c, i) {
var total = c.reduce(function(total, obj) {
for (var k in obj) {
total += obj[k];
}
return total;
}, 0);
// Format object in any format you want
var tmp = {};
tmp.name = "Week " + (i+1)
tmp.total = total;
// Push formatted object in array
p.push(tmp)
return p;
}, [])
console.log(result)
Note, I'd suggest you to use an object instead of array of objects. Benefit of this would be that you will not require to loop over output to get value. You can directly so result['week'+index]
var data=[[{"2017-01-05":607},{"2017-01-06":430},{"2017-01-07":357},{"2017-01-08":277}],[{"2017-01-09":407},{"2017-01-10":430},{"2017-01-11":357},{"2017-01-12":277}]];
var result = data.reduce(function(p, c, i) {
var total = c.reduce(function(total, obj) {
for (var k in obj) {
total += obj[k];
}
return total;
}, 0);
p["week" + (i + 1)] = total;
return p;
}, {})
console.log(result)
the variable weeks should hold what you want...
I'm assuming the week number is the actual week number in the year and not some index in the array. I'd also not use the same data structure but am adapting so that you won't need to change your structure.
var arr = [
[{
"2017-01-05": 607
}, {
"2017-01-06": 430
}, {
"2017-01-07": 357
}, {
"2017-01-08": 277
}],
[{
"2017-01-09": 607
}, {
"2017-01-10": 430
}, {
"2017-01-11": 357
}, {
"2017-01-12": 277
}]
]
function week(d) {
// taken from http://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
d.setHours(0, 0, 0, 0);
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
return Math.ceil((((d - new Date(d.getFullYear(), 0, 1)) / 8.64e7) + 1) / 7);
}
var weeks = {};
for (var x in arr) {
var subarr = arr[x]
for (var y in subarr) {
var obj = subarr[y];
for (var when in obj) {
var d = new Date(when);
var which_week = "Week " + week(d);
if (which_week in weeks) {
weeks[which_week] += obj[when];
} else {
weeks[which_week] = obj[when];
}
}
}
}
without forEach
var arrs = [
[{
"2017-01-05": 607
}, {
"2017-01-06": 430
}, {
"2017-01-07": 357
}, {
"2017-01-08": 277
}],
[{
"2017-01-09": 607
}, {
"2017-01-10": 430
}, {
"2017-01-11": 357
}, {
"2017-01-12": 277
}]
];
function loop1(arr, i, r){
r = (r ? r : 0) + arr[i][Object.keys(arr[i])[0]];
return ++i == arr.length ? r : loop1(arr, i, r);
}
function loop2(arrs, i, r){
i = i ? i : 0;
r = r ? r : {};
r['Week ' + (i + 1)] = loop1(arrs[i], 0);
return ++i == arrs.length ? r : loop2(arrs, i, r);
}
var newArr = loop2(arrs);
I have an array with below elements. I am trying to create an object from the array
var arr = [
'find({ qty: { $lt: 20 } } )',
'limit(5)',
'skip(0)'
]
Below is my code. where I am getting only values as the output. Any help on this will be helpful
for (var i = 0; i < arr.length; i++) {
var res = arr[i].search(/\(/ig)
if (res!= -1) {
var result = arr[i].split("(");
result = result[1].slice(0, -1))
}
}
Expected Output
{
"action": "find",
"value": "{ qty: { $lt: 20 } }",
"limit": 5,
"skip": 0
}
match is better than split for this kind of stuff
var arr = [
'find({ qty: { $lt: 20 } } )',
'limit(5)',
'skip(0)'
]
var obj = {};
arr.forEach(function(x, n) {
var m = x.match(/(\w+)\(\s*(.+?)\s*\)/);
if(n == 0) {
obj.action = m[1];
obj.value = m[2];
} else
obj[m[1]] = m[2];
});
document.write("<pre>" + JSON.stringify(obj,0,3));
see this fiddle
Just check if element is first in array, if yes, set action and value keys to splitted array, else just assign splitted values to key and value respectively
var arr = [
'find({ qty: { $lt: 20 } } )',
'limit(5)',
'skip(0)'
]
var result = {};
for (var i = 0; i < arr.length; i++) {
var res = arr[i].split("(")
console.log(res)
result[res[0]] = res[1].split(')')[0]
}
document.write(JSON.stringify(result))
I have an array of time that I get from the database and pass it to the javascript.when I alert the array variable I get the array of times(in my case 2 different times say 12:00 and 14:30),let the array be newdate.
In the javascript I also take in the another time say date=(12:00) I want to compare both the timings.both the values in newdate compare with date.
How to do it?
I tried the following
var newdate = new Array();
newdate = $('#newdate').val();
for(i=0;i<newdate.length;i++) {
alert(newdate[i]);
}
if (newdate >= date) {
alert("enable");
}
else {
alert("disbale");
}
when I ALERT the above I get 1,2,:,0,0 which is wrong,I want 12:00
Problem
Consider the following samples :
var string = '12:30';
for (var i = 0; i < string.length; i++) {
console.log(string[i]); // will print each character separately
}
var array = ['12:30']; // array of strings
for (var i = 0; i < array.length; i++) {
console.log(array[i]); // will print "12:30"
}
In the first case, replacing '12:30' with ['1', '2', ':', '3', '0'] will give the same result, in other words, looping through a string is like looping through an array of characters. Knowing that, let's return back to your own code :
// newdate is an empty array -> []
var newdate = new Array();
// ... then newdate is overwritten with a string -> "12:00"
newdate = $('#newdate').val();
// ... then newdate is traversed -> ["1", "2", ":", "0", "0"]
Solution
Here is how you could test a time against a collection :
var temp, item, gte;
var time = '12:15';
var collection = ['12:45', '12:00', '12:15', '12:30', '13:00', '11:00'];
var temp = time.split(':');
for (var i = 0; i < collection.length; i++) {
item = collection[i].split(':');
gte = +temp[0] >= +item[0];
if (gte) gte = +temp[1] >= +item[1];
// if (gte) gte = +temp[2] >= +item[2]; // uncomment to check seconds
if (gte) alert(time + ' >= item #' + i);
}
The above code will alert three times :
12:15 >= item #1
12:15 >= item #2
12:15 >= item #5
Going further
Reduces the collection to times that pass the function's test :
function filter(collection, fn) {
var i = 0,
l = collection.length,
result = [],
item;
for (; i < l; i++) {
item = collection[i];
if (fn(item, i)) result.push(item);
}
return result;
}
Returns a test function for times greater than or equal to the passed one :
function gte(time) {
time = time.split(':');
return function (item) {
item = item.split(':');
return +time[0] < +item[0] || (
+time[0] === +item[0] && +time[1] <= +item[1]
);
};
}
Returns a test function for times lower than or equal to the passed one :
function lte(time) {
time = time.split(':');
return function (item) {
item = item.split(':');
return +time[0] >= +item[0] && +time[1] >= +item[1];
};
}
Usage examples :
var collection = ['12:45', '12:00', '12:15', '12:30', '13:00', '11:00'];
var gteNoon = filter(collection, gte('12:00'));
var lteNoon = filter(collection, lte('12:00'));
var aroundNoon = filter(collection, function (time) {
return time.slice(0, 2) === '12';
});
gteNoon; // ["12:45", "12:00", "12:15", "12:30", "13:00"]
lteNoon; // ["12:00", "11:00"]
aroundNoon; // ["12:45", "12:00", "12:15", "12:30"]
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.
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!
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/
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
creates an array out of the Date keys,
Sorts them
Iterates over them
If the difference of the Current and Last Date is greate than a day
Push a new Array to the Sequence Array
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
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/
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
// 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++;
}
}