如何根据选中日期筛选含连续日期键的对象(值为数组)
问题描述
我有一个键为日期字符串、值为数组的对象:
{ "2023-02-10": [{…}, {…}, {…}], "2023-02-13": [{…}, {…}], "2023-02-19": [{…}, {…}, {…}], "2023-02-27": [{…}, {…}, {…}], "2023-03-02": [{…}, {…}, {…}, {…}], "2023-03-03": [{…}, {…}, {…}, {…}], "2023-03-04": [{…}, {…}, {…}, {…}], "2023-03-18": [{…}, {…}, {…}, {…}] }
需求如下:
- 用户在UI中选择一个日期后,若选中日期的前后相邻日期键不连续(例如选中
2023-02-10,下一个日期是2023-02-13,间隔超过1天),则仅返回该选中日期的键值对。 - 若选中日期存在连续的日期键(例如选中
2023-03-02,后续有2023-03-03、2023-03-04,彼此间隔1天),则返回该日期及所有连续日期的键值对(包含嵌套数组内容)。
我尝试用reduce结合date-fns的differenceInDays实现,但始终没解决,求帮助。
解决方案
可以按以下步骤实现,基于date-fns工具库:
- 提取并排序日期键:先把对象的所有日期键提取出来,转换成Date对象后排序,确保日期顺序正确。
- 定位选中日期的位置:在排序后的日期列表中找到用户选中日期的索引。
- 向前/向后查找连续日期:从选中日期的位置开始,分别向前和向后遍历,判断相邻日期的间隔是否为1天,收集所有连续的日期。
- 生成结果对象:根据收集到的连续日期,从原对象中提取对应的键值对。
代码示例
import { parseISO, differenceInDays } from 'date-fns'; const getContinuousDateEntries = (dateObj, selectedDateStr) => { // 提取并排序日期键 const sortedDates = Object.keys(dateObj) .map(dateStr => parseISO(dateStr)) .sort((a, b) => a - b); // 转换选中日期为Date对象并定位索引 const selectedDate = parseISO(selectedDateStr); const selectedIndex = sortedDates.findIndex(date => date.getTime() === selectedDate.getTime()); if (selectedIndex === -1) return {}; // 选中日期不存在时返回空对象 // 收集所有连续日期 const continuousDates = [sortedDates[selectedIndex]]; // 向后遍历找连续日期 let nextIndex = selectedIndex + 1; while (nextIndex < sortedDates.length) { const prevDate = continuousDates[continuousDates.length - 1]; const currentDate = sortedDates[nextIndex]; if (differenceInDays(currentDate, prevDate) === 1) { continuousDates.push(currentDate); nextIndex++; } else { break; } } // 若需要包含选中日期之前的连续日期,取消以下注释 // let prevIndex = selectedIndex - 1; // while (prevIndex >= 0) { // const nextDate = continuousDates[0]; // const currentDate = sortedDates[prevIndex]; // if (differenceInDays(nextDate, currentDate) === 1) { // continuousDates.unshift(currentDate); // prevIndex--; // } else { // break; // } // } // 生成结果对象 return continuousDates.reduce((result, date) => { const dateStr = date.toISOString().split('T')[0]; result[dateStr] = dateObj[dateStr]; return result; }, {}); }; // 测试示例 const data = { "2023-02-10": [1,2,3], "2023-02-13": [4,5], "2023-02-19": [6,7,8], "2023-02-27": [9,10,11], "2023-03-02": [12,13,14,15], "2023-03-03": [16,17,18,19], "2023-03-04": [20,21,22,23], "2023-03-18": [24,25,26,27] }; // 测试选中非连续日期 console.log(getContinuousDateEntries(data, "2023-02-10")); // 输出:{"2023-02-10": [1,2,3]} // 测试选中连续日期 console.log(getContinuousDateEntries(data, "2023-03-02")); // 输出:{"2023-03-02": [...], "2023-03-03": [...], "2023-03-04": [...]}
说明
- 代码默认只向后查找连续日期,若需要包含选中日期之前的连续日期(比如选中
2023-03-03时同时返回2023-03-02),可取消向前遍历的注释代码。 - 使用
parseISO处理日期字符串,确保跨环境的日期解析一致性。 - 通过
getTime()判断日期是否相等,避免时区差异导致的Date对象比较误差。
内容的提问来源于stack exchange,提问作者Matthew Ellis
相关产品推荐
相关产品推荐

