【问题标题】:Filter and map data according to the interval of the weeks of the month根据月份的周间隔过滤和映射数据
【发布时间】:2022-01-08 01:49:16
【问题描述】:

我有一个对象数组,每个对象都有四个属性(id、start、end 和 amount)。

然后根据这些数据创建一个新的对象数组,该数组具有以下属性:日期、持续时间和金额。 date 是 start 属性的时间戳的日期,duration 是 start 时间戳和 end 时间戳之间的时间,以分钟为单位。

然后我创建了两个变量,一个来自所选月份,另一个来自所选年份。然后根据选定的月份和年份过滤数组日期。例如,如果选择了第 11 个月,我只想要日期从第 11 个月开始的对象。这同样适用于年份。最终结果是根据所选月份和年份的日期列表。

const arrayOfDates = [
    {
        id: 1,
        start: '2021-12-01T12:10:56+0000',
        end: '2021-12-01T12:00:56+0000',
        amount: 10
    },
    {
        id: 2,
        start: '2021-12-03T11:10:56+0000',
        end: '2021-12-03T12:45:56+0000',
        amount: 4
    },
    {
        id: 3,
        start: '2021-12-07T09:10:56+0000',
        end: '2021-12-07T09:25:56+0000',
        amount: 8
    },
    {
        id: 4,
        start: '2021-11-24T11:10:56+0000',
        end: '2021-11-24T11:25:56+0000',
        amount: 8
    }
]

const selectedMonth = 12
const selectedYear = 2021

const mapped = arrayOfDates.map((el) => ({
    date: new Date(el.start).toLocaleDateString('en-CA'),
    duration: new Date(new Date(el.end).getTime() - new Date(el.start).getTime()).getMinutes(),
    amount: el.amount
}))

const filteredBySelectedDate = mapped.filter((el) => {
    var [year, month] = el.date.split('-')
    return selectedMonth === +month && selectedYear === +year;
})

const mappedByDays = filteredBySelectedDate

但是,除了按天列出数组的元素(这是我目前的结果)。我想使用filteredBySelectedDate 数组按周过滤。换句话说,我想根据一个月的周数范围对数组的元素进行分组。像这样的数组:

const mappedByWeeks = [
    {
        interval: '12/01 - 12/04',
        duration: 85,
        amount: 14
    },
    {
        interval: '12/05 - 12/11',
        duration: 15,
        amount: 8
    }
]

【问题讨论】:

    标签: javascript arrays typescript javascript-objects


    【解决方案1】:

    这可以通过几个步骤来完成。首先,为每个月的每个星期建立已知的开始/结束日期 (weekTransitionDays)。其次,一种识别条目属于哪一周的方法(getWeekIndex)。最后是一种将同一周的条目折叠在一起的方法 (groupByWeek)。

    编辑

    添加了用于创建间隔文本的辅助函数。

    const arrayOfDates = [{
        id: 1,
        start: '2021-12-01T12:10:56+0000',
        end: '2021-12-01T12:00:56+0000',
        amount: 10
      },
      {
        id: 2,
        start: '2021-12-03T11:10:56+0000',
        end: '2021-12-03T12:45:56+0000',
        amount: 4
      },
      {
        id: 3,
        start: '2021-12-07T09:10:56+0000',
        end: '2021-12-07T09:25:56+0000',
        amount: 8
      },
      {
        id: 4,
        start: '2021-11-24T11:10:56+0000',
        end: '2021-11-24T11:25:56+0000',
        amount: 8
      }
    ];
    
    const selectedMonth = 12;
    const selectedYear = 2021;
    
    const weekTransitionDays = [];
    const firstDayOfMonth = (new Date(selectedYear, selectedMonth - 1, 1)).getDay();
    const daysInMonth = (new Date(selectedYear, selectedMonth, 0)).getDate();
    
    const getInterval = (start, end) => {
      if (start < 10) {
        start = "0" + start;
      }
      if (end < 10) {
        end = "0" + end;
      }
      start = selectedMonth + "/" + start;
      end = selectedMonth + "/" + end;
      return start + ' - ' + end;
    };
    
    let start = 1;
    if (firstDayOfMonth !== 0) {
      let end = start + 6 - firstDayOfMonth;
      const interval = getInterval(start, end);
      weekTransitionDays.push({
        start,
        end,
        interval
      });
      start = end;
    }
    
    while (start < daysInMonth) {
      let end;
      if (start + 1 < daysInMonth) {
        start++;
      } else {
        break;
      }
      if (start + 6 < daysInMonth) {
        end = start + 6;
      } else {
        break;
      }
      const interval = getInterval(start, end);
      weekTransitionDays.push({
        start,
        end,
        interval
      });
      start = end;
    }
    
    if (weekTransitionDays.at(-1).end !== daysInMonth) {
      const end = daysInMonth;
      const interval = getInterval(start, end);
      weekTransitionDays.push({
        start,
        end,
        interval
      });
    }
    
    const getWeekIndex = entry => {
      const entryStart = new Date(entry.start).getDate();
      for (let i = 0; i < weekTransitionDays.length; i++) {
        if (weekTransitionDays[i].start <= entryStart && entryStart <= weekTransitionDays[i].end) {
          return i;
        }
      }
      // Throw error if start date doesn't line up
      throw new Error("entry.start mismatch with transition days: \n" + JSON.stringify(entry) + "\n" + JSON.stringify(weekTransitionDays));
    };
    
    const mapped = arrayOfDates.map((el) => ({
      date: new Date(el.start).toLocaleDateString('en-CA'),
      duration: new Date(new Date(el.end).getTime() - new Date(el.start).getTime()).getMinutes(),
      weekIndex: getWeekIndex(el),
      amount: el.amount
    }));
    
    const filteredBySelectedDate = mapped.filter((el) => {
      var [year, month] = el.date.split('-');
      return selectedMonth === +month && selectedYear === +year;
    });
    
    const groupByWeek = () => {
      const obj = {};
      filteredBySelectedDate.forEach(entry => {
        if (!obj.hasOwnProperty(entry.weekIndex)) {
          obj[entry.weekIndex] = {
            interval: weekTransitionDays[entry.weekIndex].interval,
            duration: 0,
            amount: 0
          };
        }
        obj[entry.weekIndex].duration += entry.duration;
        obj[entry.weekIndex].amount += entry.amount;
      });
      return Object.values(obj);
    };
    
    const mappedByDays = filteredBySelectedDate;
    const groupedByWeek = groupByWeek(mapped);
    
    console.log(groupedByWeek);

    【讨论】:

    • 非常感谢!在 groupByWeek 函数中,如果 weekIndex 未定义,可以做什么?
    • @learnbydoing 刚刚注意到重构中的一个错误。看看是否有帮助。如果您仍然有问题,那么这可能是我没有考虑过的边缘情况。
    • @learnbydoing 更新了getWeekIndex 以在任何不匹配的情况下抛出错误,以帮助调试。
    猜你喜欢
    • 2014-03-15
    • 2021-11-25
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    • 2021-11-01
    • 2020-06-23
    • 2020-12-15
    相关资源
    最近更新 更多