Как добавить количество за ту же неделю, используя reduce JavaScript?

#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);
  

Текущий результат

введите описание изображения здесь

Желаемый результат

 [
  { 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));
  

Комментарии:

1. У вас есть функция, которая создает первый день недели из номера недели?

2. @SalmanA вот функция, о которой вы просите getWeekStart(date) . У меня уже есть решение, но оно решается в два этапа. Я не думаю, что это лучшее решение. Если бы вы могли предложить лучшее решение, я был бы признателен. Существует также решение, предоставленное @Nina Scholz, но, по правде говоря, я его не совсем понимаю. К сожалению, слишком сложно для моего уровня

Ответ №1:

Вы могли бы взять день недели в качестве смещения и вычесть миллисекунды из заданной даты.

Сокращение работает с обратным вызовом и clsoure над ключом с датой начала недели.

 (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; }  

Комментарии:

1. это работает, но я не совсем понимаю, как это работает; (

2. Я приму ответ, но, по правде говоря, я впервые вижу такой синтез. Я действительно этого не понимаю.