Angular中使用RxJS按数值范围分组数据的实现问题
使用RxJS实现按数值范围分组统计的解决方案
先修正原始数据的语法问题(bugid值需为字符串,否则会触发未定义变量错误),然后通过以下步骤实现需求:
import { from, forkJoin } from 'rxjs'; import { distinct, toArray, map, filter, groupBy, mergeMap, reduce } from 'rxjs/operators'; // 修正后的原始数据 const bugs = [ { bugid: 'b1', state: 'foo', days: 2 }, { bugid: 'b2', state: 'bar', days: 41 }, { bugid: 'b3', state: 'foo', days: 45 } ]; // 定义数值范围判断逻辑 const getRange = (days) => { if (days >= 0 && days <= 25) return '0-25'; if (days >= 26 && days <= 50) return '26-50'; return null; // 超出目标范围的条目将被忽略 }; // 获取所有唯一的state类型(保证每个范围组都包含所有state统计) const uniqueStates$ = from(bugs).pipe( distinct(bug => bug.state), toArray() ); // 按范围分组并统计每个范围内各state的出现次数 const rangeStats$ = from(bugs).pipe( // 为每个条目分配对应的范围标签 map(bug => ({ ...bug, range: getRange(bug.days) })), // 过滤掉不在目标范围内的条目 filter(item => item.range !== null), // 按范围标签分组 groupBy(item => item.range), // 对每个分组内的state进行计数 mergeMap(group => group.pipe( reduce((acc, item) => { acc[item.range] = acc[item.range] || {}; acc[item.range][item.state] = (acc[item.range][item.state] || 0) + 1; return acc; }, {}) ) ), // 合并所有分组的统计结果 reduce((finalAcc, current) => ({ ...finalAcc, ...current }), {}) ); // 合并结果并转换为目标格式(补全count为0的state条目) forkJoin([uniqueStates$, rangeStats$]).pipe( map(([states, stats]) => { const result = {}; // 预先定义需要的所有范围(确保即使无数据也会生成对应键) const predefinedRanges = ['0-25', '26-50']; predefinedRanges.forEach(range => { result[range] = states.map(state => ({ name: state, value: stats[range]?.[state] || 0 })); }); return result; }) ).subscribe(finalResult => { console.log(finalResult); // 输出结果: // { // '0-25': [{ name: 'foo', value: 1 }, { name: 'bar', value: 0 }], // '26-50': [{ name: 'foo', value: 1 }, { name: 'bar', value: 1 }] // } });
核心逻辑说明
- 提取唯一state:通过
distinct操作符获取所有不重复的状态类型,确保每个范围组都能覆盖全部state的统计(包括数量为0的情况)。 - 范围映射与分组:为每个数据项标记所属范围,再通过
groupBy按范围分组,最后用reduce统计每个分组内各state的出现次数。 - 补全空统计:结合预定义的范围列表,为每个范围生成包含所有state的统计数组,不存在的state自动赋值为0。
内容的提问来源于stack exchange,提问作者confused_dude_13
相关产品推荐
相关产品推荐

