TypeScript改造数组过滤方法 实现多条件同时匹配返回对应对象
对象数组多筛选值全匹配过滤实现
现有逻辑说明
现有测试数据:
arr = [ {name: "tom", tools:["spanner", "hammer", "screwdriver"]}, {name: "john", tools:["Mallet", "hammer", "screwdriver"]}, {name: "phil", tools:["Mallet", "Drill", "screwdriver"]} ]
原有过滤方法:
private filterObjectArray(arr: any, filterArr: any): any { return arr.filter((el: any) => filterArr.some( (f: any) => el.tools.toString()?.toLowerCase().indexOf(f.name?.toLowerCase()) >= 0 ) ); }
原方法基于Array.some()实现任意匹配逻辑:传入筛选参数filterArr = [{name: "screwdriver"}, {name: "hammer"}]时,只要元素的tools属性包含任意一个筛选值就会被返回。由于三个元素都包含screwdriver,最终全部被命中,不符合要求。
需求是调整为全匹配逻辑:仅当对象的tools属性同时包含filterArr中所有筛选值时才返回,上述筛选条件下,应仅返回同时持有screwdriver和hammer的tom、john,仅持有screwdriver的phil需要被排除。
实现代码
核心改动两点:
- 把匹配判断从
some()(任意项满足即通过)替换为every()(所有项都满足才通过) - 废弃原有的
toString()转字符串匹配的写法,避免子串误判(比如筛选hammer时错误匹配到包含jackhammer的条目),转用Set做存在性校验,准确率和性能都更好。
修改后的完整方法:
private filterObjectArray(arr: any[], filterArr: Array<{name: string}>): any[] { // 提前统一处理筛选值为小写,过滤空值,避免循环内重复计算 const validFilterValues = filterArr .map(item => item.name?.toLowerCase()) .filter(Boolean); return arr.filter(element => { // 将当前元素的工具列表统一转小写存入Set,做存在性判断效率更高 const lowerToolSet = new Set( element.tools.map((tool: string) => tool.toLowerCase()) ); // 必须所有筛选值都在工具列表中存在,才保留当前元素 return validFilterValues.every(filterVal => lowerToolSet.has(filterVal)); }); }
效果验证
传入筛选参数[{name: "screwdriver"}, {name: "hammer"}]时:
- tom的工具列表包含两个筛选值,保留
- john的工具列表包含两个筛选值,保留
- phil的工具列表仅包含
screwdriver,缺少hammer,被过滤
完全符合预期。
可选适配:如果业务要求传入空筛选数组时返回空结果,只需要在方法最开头加一行判断即可:
if (validFilterValues.length === 0) return []
内容的提问来源于stack exchange,提问作者Tom Rudge
相关产品推荐
相关产品推荐

