在Observable中使用map()迭代时返回多个值的解决方案
问题描述
我有以下源自Firebase的数据:
const agendaDates = ['2022-12-10', '2022-12-11', '2022-12-12', '2022-12-13'] const events = [ { id: '001', fromDate: '2022-12-10', toDate: '2022-12-11', }, { id: '002', fromDate: '2022-12-12', toDate: '2022-12-13', }, { id: '003', fromDate: '2022-12-12', toDate: '2022-12-12', }, ]
希望将这些数据组合成如下指定结果:
const result = [ { "agendaDate": "2022-12-10", "id": "001", "fromDate": "2022-12-10", "toDate": "2022-12-11" }, { "agendaDate": "2022-12-11", "id": "001", "fromDate": "2022-12-10", "toDate": "2022-12-11" }, { "agendaDate": "2022-12-12", "id": "002", "fromDate": "2022-12-12", "toDate": "2022-12-13" }, { "agendaDate": "2022-12-12", "id": "003", "fromDate": "2022-12-12", "toDate": "2022-12-12" }, { "agendaDate": "2022-12-13", "id": "002", "fromDate": "2022-12-12", "toDate": "2022-12-13" } ]
当前使用array.map()遍历agendaDates的createAgenda方法,在同一天存在多个事件时无法正常工作:
private createAgenda(): Observable<any[]> { return combineLatest([of(agendaDates), of(events)], (agendaDates, events) => ( agendaDates.map( agDate => ( { agendaDate: agDate, ...events.find( event => { return (this.isDateInRange(agDate, event.fromDate, event.toDate)) ? event : false } ) } ) ).filter(ev => ev.id != null) ) ) }
日期范围检查辅助方法:
private isDateInRange(date: string, startDate: string, endDate: string): boolean { if (date !== undefined && startDate !== undefined && endDate !== undefined) { return (new Date(date) >= new Date(startDate) && new Date(date) <= new Date(endDate)) } else return false }
请问实现该需求的最优方案是什么?
最优解决方案
问题根源
当前代码使用events.find(),该方法只会返回第一个匹配的事件,导致同一天有多个事件时,后续事件被忽略,无法生成对应的条目。
改进思路
遍历每个日程日期,对每个日期找到所有匹配的事件,为每个匹配事件生成一条包含agendaDate的记录,最后将所有记录合并为一个数组。
代码实现
private createAgenda(): Observable<any[]> { return combineLatest([of(agendaDates), of(events)], (dates, events) => { // 遍历每个日程日期,扁平化处理匹配的事件条目 return dates.flatMap(date => { // 筛选当前日期下所有符合范围的事件 const matchedEvents = events.filter(event => this.isDateInRange(date, event.fromDate, event.toDate)); // 为每个匹配事件添加agendaDate字段 return matchedEvents.map(event => ({ agendaDate: date, ...event })); }); } ); }
关键优化点
- 使用
flatMap替代map:将每个日期对应的多个事件数组扁平化为单个条目数组,避免嵌套结构。 - 使用
filter替代find:返回所有匹配的事件,确保同一天的多个事件都能生成对应的记录。 - 保留原
isDateInRange方法:日期范围校验逻辑正确,可直接复用。
验证结果
运行上述代码后,将生成与预期完全一致的结果数组,包含所有日期对应的事件条目,包括同一天的多个事件。
内容的提问来源于stack exchange,提问作者RePLaY
相关产品推荐
相关产品推荐

