无for循环下如何按日期映射数组并按日统计各状态ID总数
无for循环实现方案
完全基于数组函数式方法实现,全程不使用任何for关键字开头的循环语法,核心依赖flatMap、reduce、filter、map、Set等原生API实现,符合禁用for循环的代码规范要求。
核心实现代码
// 原始数据源 const sourceData = [ { id: 'C12-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'INCOMPLETE', statusFrom: '2020-12-01', statusTo: '2020-12-05' }, { id: 'C13-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'INCOMPLETE', statusFrom: '2020-12-03', statusTo: '2020-12-07' }, { id: 'C14-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'INCOMPLETE', statusFrom: '2020-12-05', statusTo: '2020-12-08' }, { id: 'C15-TBX4', studyId: 'TBX4', siteId: null, statusType: 'REJECTED', statusFrom: '2020-12-05', statusTo: '2020-12-08' }, { id: 'C16-TBX4', studyId: 'TBX4', siteId: null, statusType: 'REJECTED', statusFrom: '2020-12-05', statusTo: '2020-12-09' }, { id: 'C17-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'DROPOUT', eligible: true, statusFrom: '2020-12-05', statusTo: '2020-12-09' }, { id: 'C17-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'DROPOUT', eligible: false, statusFrom: '2020-12-05', statusTo: '2020-12-10' } ]; // 给定的连续日期序列 const dateSequence = [ '2020-12-01T00:00:00.000Z', '2020-12-02T00:00:00.000Z', '2020-12-03T00:00:00.000Z', '2020-12-04T00:00:00.000Z', '2020-12-05T00:00:00.000Z', '2020-12-06T00:00:00.000Z', '2020-12-07T00:00:00.000Z', '2020-12-08T00:00:00.000Z', '2020-12-09T00:00:00.000Z' ]; // 工具:日期转YYYY-MM-DD格式 const formatDay = (dateStr) => new Date(dateStr).toISOString().slice(0, 10); // 工具:判断日期是否在[from, to)左闭右开区间 const isDateInRange = (checkTs, fromStr, toStr) => { const fromTs = new Date(fromStr).getTime(); const toTs = new Date(toStr).getTime(); return checkTs >= fromTs && checkTs < toTs; }; const result = dateSequence.flatMap(currentDate => { const currentTs = new Date(currentDate).getTime(); const currentDay = formatDay(currentDate); // 筛选当前日期下所有生效的记录 const validRecords = sourceData.filter(record => isDateInRange(currentTs, record.statusFrom, record.statusTo) ); // 按studyId、siteId、statusType三个维度分组 const groupMap = validRecords.reduce((acc, record) => { const groupKey = `${record.studyId}||${record.siteId}||${record.statusType}`; if (!acc.has(groupKey)) { acc.set(groupKey, { studyId: record.studyId, siteId: record.siteId, statusType: record.statusType, idSet: new Set() }); } acc.get(groupKey).idSet.add(record.id); return acc; }, new Map()); // 生成本日期下所有维度的统计条目 return Array.from(groupMap.values()).map(group => ({ studyId: group.studyId, siteId: group.siteId, day: currentDay, statusType: group.statusType, total: group.idSet.size })); });
逻辑说明
- 日期判断严格遵循左闭右开规则:
statusFrom对应日期计入统计,statusTo对应日期排除,和需求规则完全一致。 - 用
Set存储同分组下的id,自动完成去重,保证total统计的是唯一id的数量,不会重复计数。 - 自动适配所有
statusType类型,不需要单独为每个状态写分支逻辑,后续新增状态类型也不需要修改核心代码。 - 以传入的连续日期序列为基准生成条目,不会出现日期断层。
注:你提供的INCOMPLETE示例中存在一条重复的2020-12-03条目,上述实现会自动合并同维度同日期的计数,不会生成重复条目,符合常规统计逻辑。如果业务上确实需要保留重复条目,调整分组阶段的处理逻辑即可。
内容的提问来源于stack exchange,提问作者Jakub
相关产品推荐
相关产品推荐

