Angular中如何基于History Observable按条目频次生成排序后的Content Observable
RxJS 实现按条目出现次数排序的Observable
核心逻辑
不需要手动订阅遍历History,直接通过RxJS内置操作符做流转换即可生成目标Content Observable,全程无额外订阅副作用,符合响应式编程规范。
单次数组内排序实现(仅统计单次发射的数组内条目频次)
适用场景:History每次发射的就是完整的全量条目数组,只需要对单次数组内的条目做频次统计、去重、排序。
- 第一步:用
map操作符接收History发射的原始条目数组 - 第二步:遍历数组,以条目
id为唯一标识统计每个id的出现次数 - 第三步:对数组做id维度去重,避免同类型条目重复出现
- 第四步:按照之前统计的出现次数做降序排序,频次越高的条目越靠前
import { Observable, map } from 'rxjs'; // 定义条目数据结构 interface HistoryEntry { id: string | number; [key: string]: any; // 三类条目共有的通用字段 } // 原始History Observable declare const History: Observable<HistoryEntry[]>; // 生成排序后的Content Observable const Content = History.pipe( map((entries) => { // 统计各id出现频次 const frequencyMap = entries.reduce((map, entry) => { map[entry.id] = (map[entry.id] ?? 0) + 1; return map; }, {} as Record<string | number, number>); // 按id去重 const uniqueEntries = Array.from( entries.reduce((map, entry) => { map.set(entry.id, entry); return map; }, new Map<string | number, HistoryEntry>()).values() ); // 按频次降序排序后返回 return uniqueEntries.sort( (prev, curr) => frequencyMap[curr.id] - frequencyMap[prev.id] ); }) );
全流累计排序实现(统计History所有历史发射条目的总频次)
适用场景:History会分批发射多组条目,需要累计所有历史数据的总出现次数再排序。
const Content = History.pipe( scan( (acc, batchEntries) => { batchEntries.forEach((entry) => { // 累计id出现次数 acc.totalFrequency[entry.id] = (acc.totalFrequency[entry.id] ?? 0) + 1; // 更新去重后的条目 acc.uniqueEntryMap.set(entry.id, entry); }); return acc; }, { totalFrequency: {} as Record<string | number, number>, uniqueEntryMap: new Map<string | number, HistoryEntry>() } ), map(({ totalFrequency, uniqueEntryMap }) => { return Array.from(uniqueEntryMap.values()).sort( (prev, curr) => totalFrequency[curr.id] - totalFrequency[prev.id] ); }) );
提示:如果需要调整排序规则,修改
sort方法内的返回值即可;如果需要保留重复条目不做去重,直接去掉去重逻辑,对原始数组按频次映射排序即可。
内容的提问来源于stack exchange,提问作者Picolo
相关产品推荐
相关产品推荐

