本文介绍在 Angular 中使用 RxJS 的 pipe() 操作符对 valueChanges 观察流进行实时过滤与去重,确保 <mat-autocomplete> 下拉选项仅显示 param2 字段的唯一值,避免重复项干扰用户体验。
本文介绍在 angular 中使用 rxjs 的 `pipe()` 操作符对 `valuechanges` 观察流进行实时过滤与去重,确保 `
在实际开发中,当基于表单控件的 valueChanges 动态过滤数据源(如 tableDataSource.data)时,常会遇到重复值问题:多个对象可能具有相同的 param2 值(例如 [{id: 1, param2: 'lorem'}, {id: 2, param2: 'lorem'}]),但下拉菜单应只呈现一个 'lorem' 选项。此时,仅靠 .filter() 进行字符串匹配是不够的——还需在结果数组上执行去重逻辑。
关键在于:将去重操作作为 pipe() 中的后续步骤,而非在模板中处理(async 管道不支持链式转换)。推荐使用 map() 结合纯函数实现去重,例如利用 Set 构造唯一值数组:
this.dropdownSingleFilteredOptions = this.tableFormGroup.controls['filterParam2'].valueChanges.pipe(
startWith(''),
map((value: string) => {
const searchTerm = (value ?? '').toLowerCase();
// 第一步:按 search term 过滤原始数据
const filtered = this.tableDataSource.data.filter(
data => data.param2?.toLowerCase().includes(searchTerm)
);
// 第二步:提取 param2 并去重(保留首次出现顺序)
return [...new Set(filtered.map(item => item.param2))].filter(Boolean);
})
);✅ 说明:[...new Set(...)] 是高效、简洁且兼容性良好的去重方式,自动剔除重复字符串;.filter(Boolean) 可额外排除空值或 undefined,增强健壮性。
⚠️ 注意事项:
- 避免在 map 内部使用 indexOf 或 findIndex 实现去重(如 filter((v, i) => arr.indexOf(v) === i)),因其时间复杂度为 O(n²),在大数据集下性能较差;
- 若需保持原始数据中 param2 的首次出现顺序(而非字典序),Set 方案天然满足该需求;
- 确保 param2 字段存在且为字符串类型,建议添加可选链 ?. 和空值校验,防止运行时错误;
- 如需支持大小写敏感搜索或更复杂的匹配逻辑(如模糊匹配),可将 includes() 替换为正则或第三方库(如 Fuse.js),但去重步骤仍应置于最终映射阶段。
综上,通过合理组合 map 与 Set,即可在响应式管道中优雅、高效地实现“搜索 + 去重”双重目标,让 <mat-autocomplete> 始终呈现干净、唯一的选项列表。

















