JS日期数组如何按天分组
Array Of JS Dates How To Group By Days
我正在尝试找出最优化和最少循环次数的方法来对我的 js 日期对象数组进行分组:(请注意,这是浏览器控制台输出,它实际上是真实的 JS 日期,如新日期日期())
[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 23:00:00 GMT+0200 (Central Europe Daylight Time)]
将同一天的每个日期组织到 "chunk" 中,这样我就可以在 UI "Aug 08" 上显示它并显示 2 个或当天有多少个日期。
例如:
[{day: 'Aug 08', times:[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time)]}]
我目前考虑的方式是
var startDays = _.map(occurences, function (date) {
return moment(date).startOf('day').format();
});
在那之后获得独特的日子:
_.uniq(startDays, true)
在我得到独特的日子之后,另一个循环将同一天添加到这个组,你现在可以看到你可能明白为什么我不喜欢它,这就是为什么我很想得到一些聪明的帮助因为我对此一无所知。谢谢。
为什么需要这个优化?如果你的数组不够大,那么你可能不需要优化你的算法。
我不熟悉给定的 js 库,但是您可以通过一个循环按天对数组进行分组。但是您需要以某种方式确定数组中的当前日期,然后使用日期字段和时间数组字段创建相应的 js 对象,然后将此对象添加到结果数组中。
如果在实现此算法之前对数组进行预排序,速度会快得多。
假设你的数据实际上是字符串,我不知道你为什么认为你需要这些库中的任何一个。您只是根据子字符串对字符串进行分组。
ES5引入reduce,非常适合积累东西:
创建日期数组的助手:
// Generate a dates array given a start date and how many to create:
function genDates(startDate, count) {
var d = new Date(+startDate),
dates = [d];
for (var i=0; i<count; i++) {
d = new Date(+d);
d.setHours(d.getHours() + 10);
dates.push(d);
}
return dates;
}
这个答案最初处理字符串,修改为与日期一起使用:
// Generate date key 'MMM dd'
// Replaces use of moment.js
function getDateKey(date) {
var d = date.getDate();
var m = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
return m[date.getMonth()] + ' ' + ((d<10?'0':'') + d);
}
// Generate an array in format [{day:'MMM dd', times:[d0, d1, ...]}, ...]
// Replaces use of underscore.js
var obj = dates.reduce(function(acc, d) {
var p = getDateKey(d)
if (!acc[0].hasOwnProperty(p)) acc[0][p] = [];
acc[0][p].push(d);
return acc;
},[{}])
.reduce(function(acc, v){
Object.keys(v).forEach(function(k){acc.push({day:k, times:v[k]})});
return acc;
},[]);
console.log(JSON.stringify(obj));
如果最佳性能是关键,以上是 20 times faster 比 5 到 100 个日期的数组的下划线 + Moment 解决方案。为了让它更快,删除所有迭代器和库的使用,并使用带有 for 循环的单个函数。请注意,上面仅比使用 Moment.js 和 underscore.js.
的解决方案多了一行代码
Underscore 具有 _.groupBy 函数,它应该完全符合您的要求:
var groups = _.groupBy(occurences, function (date) {
return moment(date).startOf('day').format();
});
这将 return 一个对象,其中每个键是一天,值是一个包含当天所有事件的数组。
要将对象转换为与问题中形式相同的数组,您可以使用 map:
var result = _.map(groups, function(group, day){
return {
day: day,
times: group
}
});
要分组、映射和排序,您可以执行以下操作:
var occurrenceDay = function(occurrence){
return moment(occurrence).startOf('day').format();
};
var groupToDay = function(group, day){
return {
day: day,
times: group
}
};
var result = _.chain(occurences)
.groupBy(occurrenceDay)
.map(groupToDay)
.sortBy('day')
.value();
如果您还需要按 年 或(和)月 和日进行分组 - 我建议使用我的解决方案。
在上面的答案中,如果您在同一天得到不同的月份或年份 - 您的分组将不正确。
看看好的解决方案:
_.groupBy(arrayOfDates, function (el) {
return (el.getFullYear() + '|y|') + (el.getMonth() + '|m|') + (el.getDate() + '|d|');
});
我在这里做什么?只需为每个日期创建一个唯一的键,其中包括:年、月和日。然后我通过这个唯一的键对数组进行分组。
result
我正在尝试找出最优化和最少循环次数的方法来对我的 js 日期对象数组进行分组:(请注意,这是浏览器控制台输出,它实际上是真实的 JS 日期,如新日期日期())
[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 23:00:00 GMT+0200 (Central Europe Daylight Time)]
将同一天的每个日期组织到 "chunk" 中,这样我就可以在 UI "Aug 08" 上显示它并显示 2 个或当天有多少个日期。
例如:
[{day: 'Aug 08', times:[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time)]}]
我目前考虑的方式是
var startDays = _.map(occurences, function (date) {
return moment(date).startOf('day').format();
});
在那之后获得独特的日子:
_.uniq(startDays, true)
在我得到独特的日子之后,另一个循环将同一天添加到这个组,你现在可以看到你可能明白为什么我不喜欢它,这就是为什么我很想得到一些聪明的帮助因为我对此一无所知。谢谢。
为什么需要这个优化?如果你的数组不够大,那么你可能不需要优化你的算法。
我不熟悉给定的 js 库,但是您可以通过一个循环按天对数组进行分组。但是您需要以某种方式确定数组中的当前日期,然后使用日期字段和时间数组字段创建相应的 js 对象,然后将此对象添加到结果数组中。 如果在实现此算法之前对数组进行预排序,速度会快得多。
假设你的数据实际上是字符串,我不知道你为什么认为你需要这些库中的任何一个。您只是根据子字符串对字符串进行分组。
ES5引入reduce,非常适合积累东西:
创建日期数组的助手:
// Generate a dates array given a start date and how many to create:
function genDates(startDate, count) {
var d = new Date(+startDate),
dates = [d];
for (var i=0; i<count; i++) {
d = new Date(+d);
d.setHours(d.getHours() + 10);
dates.push(d);
}
return dates;
}
这个答案最初处理字符串,修改为与日期一起使用:
// Generate date key 'MMM dd'
// Replaces use of moment.js
function getDateKey(date) {
var d = date.getDate();
var m = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
return m[date.getMonth()] + ' ' + ((d<10?'0':'') + d);
}
// Generate an array in format [{day:'MMM dd', times:[d0, d1, ...]}, ...]
// Replaces use of underscore.js
var obj = dates.reduce(function(acc, d) {
var p = getDateKey(d)
if (!acc[0].hasOwnProperty(p)) acc[0][p] = [];
acc[0][p].push(d);
return acc;
},[{}])
.reduce(function(acc, v){
Object.keys(v).forEach(function(k){acc.push({day:k, times:v[k]})});
return acc;
},[]);
console.log(JSON.stringify(obj));
如果最佳性能是关键,以上是 20 times faster 比 5 到 100 个日期的数组的下划线 + Moment 解决方案。为了让它更快,删除所有迭代器和库的使用,并使用带有 for 循环的单个函数。请注意,上面仅比使用 Moment.js 和 underscore.js.
的解决方案多了一行代码Underscore 具有 _.groupBy 函数,它应该完全符合您的要求:
var groups = _.groupBy(occurences, function (date) {
return moment(date).startOf('day').format();
});
这将 return 一个对象,其中每个键是一天,值是一个包含当天所有事件的数组。
要将对象转换为与问题中形式相同的数组,您可以使用 map:
var result = _.map(groups, function(group, day){
return {
day: day,
times: group
}
});
要分组、映射和排序,您可以执行以下操作:
var occurrenceDay = function(occurrence){
return moment(occurrence).startOf('day').format();
};
var groupToDay = function(group, day){
return {
day: day,
times: group
}
};
var result = _.chain(occurences)
.groupBy(occurrenceDay)
.map(groupToDay)
.sortBy('day')
.value();
如果您还需要按 年 或(和)月 和日进行分组 - 我建议使用我的解决方案。
在上面的答案中,如果您在同一天得到不同的月份或年份 - 您的分组将不正确。
看看好的解决方案:
_.groupBy(arrayOfDates, function (el) {
return (el.getFullYear() + '|y|') + (el.getMonth() + '|m|') + (el.getDate() + '|d|');
});
我在这里做什么?只需为每个日期创建一个唯一的键,其中包括:年、月和日。然后我通过这个唯一的键对数组进行分组。
result