React.js中根据输入日期动态生成按年份分类统计表格的方法
日期区间按年份分类统计实现方案
实现逻辑拆解
- 预处理输入参数:将用户传入的起止日期字符串统一转为时间对象,计算区间覆盖的连续年份列表,比如输入
2020-05-15到2022-05-30时,覆盖年份为[2020, 2021, 2022],无需遍历全量数据提取年份。 - 过滤+聚合数据:遍历原始JSON数组,先判断每条记录的日期是否落在起止区间内,过滤掉区间外的数据;对符合条件的记录,按「记录年份+category分类」两个维度做计数累加。
- 动态渲染表格:表头以分类列为首列,后续按顺序排列覆盖到的年份,可按需增加合计列;逐行填充每个分类在对应年份的统计值,最后可增加总计行统计各年份的总记录数。
可直接复用的代码示例(JavaScript实现)
// 原始数据源 const rawData = [ {"id" : "1", "category" : "A", "Date" : "2000-02-20"}, {"id" : "2", "category" : "B", "Date" : "2000-03-11"}, {"id" : "3", "category" : "C", "Date" : "2000-05-11"}, {"id" : "4", "category" : "C", "Date" : "2010-01-20"}, {"id" : "5", "category" : "A", "Date" : "2010-04-02"}, {"id" : "6", "category" : "B", "Date" : "2010-06-10"}, {"id" : "998", "category" : "C", "Date" : "2022-08-14"}, {"id" : "999", "category" : "B", "Date" : "2022-09-15"}, {"id" : "1000", "category" : "A", "Date" : "2022-07-10"} ]; /** * 生成区间统计结果 * @param {string} startStr 起始日期 格式YYYY-MM-DD * @param {string} endStr 结束日期 格式YYYY-MM-DD * @returns {object} 包含年份列表、分类列表、统计二维数组的结果 */ function getRangeStats(startStr, endStr) { const start = new Date(startStr); const end = new Date(endStr); // 生成覆盖的年份列表 const startYear = start.getFullYear(); const endYear = end.getFullYear(); const coverYears = Array.from({length: endYear - startYear + 1}, (_,i) => startYear + i); // 提取所有分类 去重 const categories = [...new Set(rawData.map(item => item.category))]; // 初始化统计对象 结构: {年份: {分类: 计数}} const stats = Object.fromEntries(coverYears.map(y => [y, Object.fromEntries(categories.map(c => [c, 0]))])); // 遍历数据过滤聚合 rawData.forEach(item => { const itemDate = new Date(item.Date); // 跳过区间外数据 if (itemDate < start || itemDate > end) return; const itemYear = itemDate.getFullYear(); stats[itemYear][item.category] += 1; }); return { coverYears, categories, stats }; } // 调用示例 输入2020-05-15到2022-05-30 const statResult = getRangeStats('2020-05-15', '2022-05-30'); /** * 动态渲染表格到页面 * @param {object} result 统计结果 */ function renderTable(result) { const { coverYears, categories, stats } = result; // 生成表头 let tableHtml = `<table border="1" cellpadding="6" cellspacing="0"><thead><tr><th>分类</th>`; coverYears.forEach(y => { tableHtml += `<th>${y}年</th>`; }); tableHtml += `<th>合计</th></tr></thead><tbody>`; // 生成分类行 categories.forEach(cate => { let rowTotal = 0; tableHtml += `<tr><td>${cate}</td>`; coverYears.forEach(y => { const count = stats[y][cate]; rowTotal += count; tableHtml += `<td>${count}</td>`; }); tableHtml += `<td>${rowTotal}</td></tr>`; }); // 生成总计行 tableHtml += `<tr><td>总计</td>`; let allTotal = 0; coverYears.forEach(y => { const yearTotal = categories.reduce((sum, c) => sum + stats[y][c], 0); allTotal += yearTotal; tableHtml += `<td>${yearTotal}</td>`; }); tableHtml += `<td>${allTotal}</td></tr></tbody></table>`; // 插入到页面body 可替换为自己的容器节点 document.body.innerHTML += tableHtml; } // 执行渲染 renderTable(statResult);
注意事项
- 日期比较时一定要转成时间对象/时间戳,不要直接比较字符串,避免跨时区、格式不一致导致的判断错误。
- 如果数据源量级超过10万条,可以先按日期做粗筛,减少遍历判断的性能消耗。
- 分类如果存在动态新增的情况,不需要提前写死分类列表,遍历聚合时动态收集去重即可。
内容的提问来源于stack exchange,提问作者Siva_K22
相关产品推荐
相关产品推荐

