【问题标题】:Array Of JS Dates How To Group By DaysJS日期数组如何按天分组
【发布时间】:2015-08-08 05:44:47
【问题描述】:

我正在尝试找出最优化且循环次数最少的方法来分组我的 js 日期对象数组:(请注意,这是浏览器控制台输出,它实际上是真正的 JS 日期,例如 new Date( ))

[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)]

将同一天的每个日期排列在一个“块”内,这样我就可以在 UI“8 月 8 日”上显示它并显示 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)

在我获得独特的日子之后,另一个循环将同一天添加到该组中,正如您现在所看到的那样,您可能会明白为什么我不喜欢它,这就是为什么我希望得到一些聪明的帮助,因为没有这让我很头疼。谢谢。

【问题讨论】:

  • 您是否考虑过使用 _.groupBy 而不是 _.map?
  • @GruffBunny 我不知道!我现在会调查一下谢谢

标签: javascript underscore.js momentjs


【解决方案1】:

Underscore 具有 _.groupBy 功能,它应该完全符合您的要求:

var groups = _.groupBy(occurences, function (date) {
  return moment(date).startOf('day').format();
});

这将返回一个对象,其中每个键是一天,值是一个包含当天所有事件的数组。

要将对象转换为与问题中相同形式的数组,您可以使用 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();

【讨论】:

  • 有没有办法取回一个数组?顺序很重要,我真的不需要为每个组提供参考,所以如果它是一个数组就可以了。尝试迭代它并且流星不支持 {{#each object}}
  • 谢谢!订单是否保证相同?希望 groupby 不能把它搞砸我认为它可能是因为它是一个对象,所以也许更安全的赌注是甚至不将它转换为对象并有一些自定义函数来正确排列数组?
  • 无法保证 javascript 对象中键的顺序,因此可以确定您可以在映射后使用 _.sorttBy。我添加了一个额外的 sn-p,它显示了使用下划线链接完成的所有操作。
  • 非常感谢您的帮助!出于好奇,有没有办法测试这有多快?我总是在脑海中限制或害怕使用太多循环,所以我想我可以给它一个测试,看看它是如何工作的:)
  • jsperf 用于试用js 性能。如果性能是一个问题,那么编写良好的纯 js 解决方案通常会更快。但是,您在性能方面获得的收益通常会在代码清晰度和表现力方面有所损失。
【解决方案2】:

假设您的数据实际上是字符串,我不知道您为什么认为您需要这些库中的任何一个。您只是根据子字符串对字符串进行分组。

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,而不是下划线 + Moment 解决方案,用于 5 到 100 个日期的数组。为了使其更快,请删除所有迭代器和库的使用,并使用带有 for 循环的单个函数。注意,上面只比使用 Moment.js 和 underscore.js 的方案多出一行代码。

【讨论】:

  • 它不是字符串,它实际上是日期对象,它只是控制台输出,因此可以使用内部时刻(日期)或简单的内置 JS 日期对象,它与新日期()相同。但是谢谢你的方式!看起来很有趣,我将尝试通过 momet() 检查在我的循环中采用这种技术。 PS这两个库都在我的项目中可用,所以使用它们只会让生活更轻松,希望下划线减少是一样的?
  • 深入研究这一点,我确实学会了一种添加和检查数组的技术,我可以明确地实现这样的工作。但 underscore 实际上有 _.groupBy 让生活更轻松。所以只是想感谢您的时间,我从中吸取了教训,将来我将能够立即在脑海中思考解决方案!
【解决方案3】:

如果您还需要按 year 或(和)month 与天进行分组 - 我建议使用我的解决方案。

在上面的答案中,如果您在同一天得到不同的月份或年份 - 您的分组将不正确。

看看好的解决方案

_.groupBy(arrayOfDates, function (el) {
      return (el.getFullYear() + '|y|') + (el.getMonth() + '|m|') + (el.getDate() + '|d|');
    });

我在这里做什么?只需为每个日期创建一个唯一键,其中包括:年、月和日。然后我按这个唯一键对数组进行分组。

result

【讨论】:

    【解决方案4】:

    为什么需要这种优化?如果您的数组不是很大,那么您可能不需要优化您的算法。

    我不熟悉给定的 js 库,但您可以通过一个循环按天对数组进行分组。但是您需要以某种方式确定数组中的当前日期,然后使用 day-field 和 times-array 字段创建相应的 js 对象,然后将此对象添加到结果数组中。 如果在实现此算法之前对数组进行预排序,速度会快得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2019-09-10
      • 1970-01-01
      相关资源
      最近更新 更多