javascript - 如何使用reduce JavaScript 添加同一周的计数?

标签 javascript

我正在尝试使用 reduce 实现一个函数,该函数允许我对对象数组进行分组 { date: '2019-03-11', count: 8 }几周。到目前为止,我能够按周对日期进行分组,但如果日期在同一周内,则无法将 count 加在一起。

const dates = [
  { date: '2019-03-11', count: 8 },
  { date: '2019-03-12', count: 7 },
  { date: '2019-03-09', count: 6 },
  { date: '2019-02-27', count: 10 },
  { date: '2019-02-26', count: 11 },
  { date: '2019-02-22', count: 12 },
  { date: '2019-04-21', count: 3 },
  { date: '2019-04-18', count: 2 },
  { date: '2019-04-17', count: 4 },
  { date: '2019-04-19', count: 5 }
];
Date.prototype.getWeek = function() {
  const onejan = new Date(this.getFullYear(), 0, 1);
  return Math.ceil(((this - onejan) / 86400000 + onejan.getDay() + 1) / 7);
};

const groups = dates.reduce(function(acc, item) {
  const today = new Date(item.date);
  const weekNumber = today.getWeek(today);
  // check if the week number exists
  if (typeof acc[weekNumber] === 'undefined') {
    acc[weekNumber] = [];
  }

  acc[weekNumber].push(item.date, item.count);

  return acc;
}, {});

console.log(groups);

当前结果

enter image description here

期望的结果

[
  { weekStart: '2019-02-17', count: 12 },
  { weekStart: '2019-02-24', count: 21 },
  { weekStart: '2019-03-03', count: 6 },
  { weekStart: '2019-03-10', count: 15 },
  { weekStart: '2019-04-14', count: 11 },
  { weekStart: '2019-04-21', count: 21 }
]

其中 weekStart 是分组的一周的第一个日期(星期日)

解决方案

const dates = [
  { date: '2019-02-24', count: 10 },
  { date: '2019-02-25', count: 11 },
  { date: '2019-02-26', count: 12 },
  { date: '2019-03-09', count: 8 },
  { date: '2019-03-10', count: 7 },
  { date: '2019-03-11', count: 6 },
  { date: '2019-04-14', count: 3 },
  { date: '2019-04-15', count: 2 },
  { date: '2019-04-16', count: 4 },
  { date: '2019-04-22', count: 5 }
];

/**
 * Returns the week number for this date.  dowOffset is the day of week the week
 * "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
 * the week returned is the ISO 8601 week number.
 * @param int dowOffset
 * @return int
 */
Date.prototype.getWeek = function(dowOffset) {
  /*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.epoch-calendar.com */

  dowOffset = typeof dowOffset == 'int' ? dowOffset : 0; //default dowOffset to zero
  var newYear = new Date(this.getFullYear(), 0, 1);
  var day = newYear.getDay() - dowOffset; //the day of week the year begins on
  day = day >= 0 ? day : day + 7;
  var daynum =
    Math.floor(
      (this.getTime() -
        newYear.getTime() -
        (this.getTimezoneOffset() - newYear.getTimezoneOffset()) * 60000) /
        86400000
    ) + 1;
  var weeknum;
  //if the year starts before the middle of a week
  if (day < 4) {
    weeknum = Math.floor((daynum + day - 1) / 7) + 1;
    if (weeknum > 52) {
      nYear = new Date(this.getFullYear() + 1, 0, 1);
      nday = nYear.getDay() - dowOffset;
      nday = nday >= 0 ? nday : nday + 7;
      /*if the next year starts before the middle of
           the week, it is week #1 of that year*/
      weeknum = nday < 4 ? 1 : 53;
    }
  } else {
    weeknum = Math.floor((daynum + day - 1) / 7);
  }
  return weeknum;
};

function getWeekStart(date) {
  var offset = new Date(date).getDay();
  return new Date(new Date(date) - offset * 24 * 60 * 60 * 1000)
    .toISOString()
    .slice(0, 10);
}

function groupWeeks(dates) {
  const groupsByWeekNumber = dates.reduce(function(acc, item) {
    const today = new Date(item.date);
    const weekNumber = today.getWeek();

    // check if the week number exists
    if (typeof acc[weekNumber] === 'undefined') {
      acc[weekNumber] = [];
    }

    acc[weekNumber].push(item);

    return acc;
  }, []);

  return groupsByWeekNumber.map(function(group) {
    return {
      weekStart: getWeekStart(group[0].date),
      count: group.reduce(function(acc, item) {
        return acc + item.count;
      }, 0)
    };
  });
}

console.log(groupWeeks(dates));

最佳答案

您可以将工作日作为偏移量,并从给定日期中减去毫秒。

通过回调和关闭带有周开始日期的键来减少工作。

(m, { date, count }) =>                      // outer callback with map and object
    (k => m.set(k, (m.get(k) || 0) + count)) // closure over k and updating the count in map
    (getWeekStart(date))                     // get value for k

function getWeekStart(date) {
    var offset = new Date(date).getDay();
    return new Date(new Date(date) - offset * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
}

const
    dates = [{ date: '2019-03-11', count: 8 }, { date: '2019-03-12', count: 7 }, { date: '2019-03-09', count: 6 }, { date: '2019-02-27', count: 10 }, { date: '2019-02-26', count: 11 }, { date: '2019-02-22', count: 12 }, { date: '2019-04-21', count: 3 }, { date: '2019-04-18', count: 2 }, { date: '2019-04-17', count: 4 }, { date: '2019-04-19', count: 5 }],
    result = Array.from(
        dates.reduce((m, { date, count }) =>
            (k => m.set(k, (m.get(k) || 0) + count))(getWeekStart(date)),
            new Map),
        ([date, count]) => ({ date, count })
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

关于javascript - 如何使用reduce JavaScript 添加同一周的计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55808224/

相关文章:

javascript - 如何使用 JS 和 NodeJS 服务器为标准 html 页面正确配置 app.yaml?

javascript - 热发送带有 cljs-ajax 的 ajax 请求,其正文键没有冒号

javascript - 如何手动触发ajax Complete事件

javascript - FullPage.js 在桌面上的淡入淡出效果,禁用并在较小的设备上获得默认滚动

javascript - 检查状态数组中是否存在元素

javascript - 无法根据两个日期在日期选择器中设置最大和最小范围

javascript - Lodash 对对象数组中的项目进行分组

当我期待 4 项时,Javascript 正则表达式仅匹配 2 项

javascript - 如何获取 map 中第一个数组索引的迭代?

javascript - 什么是 block 作用域函数ECMAScript 6与ECMAScript 5的比较