如何基于Observable返回的实验数据计算各实验通过用户的平均尝试次数
问题解答
是否可以通过简单subscribe实现
完全可以实现,直接在subscribe的next回调中完成过滤、分组、均值计算逻辑即可,示例代码如下:
// 假设experimentalResult$为你的源Observable,一次性发射所有用户的实验结果数组 experimentalResult$.subscribe({ next: (allUserResults: experimentalresult[]) => { // 初始化分组容器:key为实验项,value存储该组总尝试次数、通过人数 const expGroup = new Map<Task, { totalAttempts: number, passCount: number }>(); // 遍历所有用户的所有实验记录 allUserResults.forEach(userResult => { userResult.Results.forEach(expRecord => { // 仅统计实验通过的记录 if (!expRecord.Status) return; // 该实验首次统计时初始化分组 if (!expGroup.has(expRecord.Experiment)) { expGroup.set(expRecord.Experiment, { totalAttempts: 0, passCount: 0 }); } const currentGroup = expGroup.get(expRecord.Experiment)!; currentGroup.totalAttempts += expRecord.Attempts; currentGroup.passCount += 1; }); }); // 按实验顺序生成平均结果数组,此处如果有固定实验排序规则,可先对expGroup的key做排序再遍历 const result = Array.from(expGroup.values()).map(group => { return (group.totalAttempts / group.passCount).toFixed(1); }); // 此处result就是你需要的格式,比如['2.7', '3.4', '2.1'] console.log(result); }, error: (err) => console.error('数据处理失败:', err) })
这种写法适合一次性使用的场景,缺点是逻辑耦合在订阅回调中,不方便复用,也难以和其他RxJS流逻辑组合。
更推荐的实现方案
建议使用RxJS操作符把处理逻辑封装在流中,后续可以直接复用处理后的流,也方便扩展其他逻辑:
import { map } from 'rxjs'; // 把数据处理逻辑放在pipe里,和订阅逻辑分离 const experimentAvg$ = experimentalResult$.pipe( map((allUserResults: experimentalresult[]) => { const expGroup = new Map<Task, { totalAttempts: number, passCount: number }>(); allUserResults.forEach(userResult => { userResult.Results.forEach(expRecord => { if (!expRecord.Status) return; if (!expGroup.has(expRecord.Experiment)) { expGroup.set(expRecord.Experiment, { totalAttempts: 0, passCount: 0 }); } const currentGroup = expGroup.get(expRecord.Experiment)!; currentGroup.totalAttempts += expRecord.Attempts; currentGroup.passCount += 1; }); }); // 如果需要固定实验顺序,比如按预设的实验列表排序,可替换为以下逻辑: // const fixedExpOrder = [Task.EXP1, Task.EXP2, Task.EXP3]; // return fixedExpOrder.map(exp => { // const group = expGroup.get(exp); // return group ? (group.totalAttempts / group.passCount).toFixed(1) : '0'; // }); return Array.from(expGroup.values()).map(group => (group.totalAttempts / group.passCount).toFixed(1)); }) ); // 订阅时直接拿到处理完成的结果 experimentAvg$.subscribe(result => console.log(result));
如果你的源Observable是逐个发射单用户的experimentalresult数据,而非一次性发射全量数组,把上述的map替换为scan操作符做累加即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者user16853055
相关产品推荐
相关产品推荐

