使用Ramda实现带过滤项追踪功能的列表过滤
使用Ramda实现带剔除追踪的多规则过滤
现有如下数据列表,需要用Ramda应用多组过滤规则,同时追踪每个过滤器剔除的项ID:
const data = [ {id: 1, name: "Andreas"}, {id: 2, name: "Antonio"}, {id: 3, name: "Bernhard"}, {id: 4, name: "Carlos"} ];
常规多过滤可以用pipe(filter(predA), filter(predB), ...)(data)实现,但这里需要给每个过滤器绑定标识,记录它剔除的项。已经定义了filterBy函数,它会返回当前过滤器的剔除记录,以及过滤后剩余的数据:
const filterBy = (key, pred) => subs => { const [res, rej] = R.partition(pred, subs); return [{[key]: rej.map(R.prop('id'))}, res]; };
现在有两个过滤器:
const isEven = filterBy('id', i => i % 2 === 0); const startsWithA = filterBy('name', R.startsWith('A'));
目标是得到包含所有剔除记录(按分组标识整理)和最终通过项的结果:
[ { id: [1, 3], name: [3, 4] }, [{id: 2, name: "Antonio"}] ]
解决方案
利用Ramda的reduce来组合这些过滤器,逐步累积剔除记录并传递过滤后的数据:
const combineFilters = (...filters) => data => { return filters.reduce( ([accRejections, currentData], filter) => { const [newRejection, filteredData] = filter(currentData); return [R.merge(accRejections, newRejection), filteredData]; }, [{}, data] ); }; // 调用组合后的过滤器 const result = combineFilters(isEven, startsWithA)(data); console.log(result);
原理说明
reduce的初始值是[{}, data],空对象用来累积所有剔除记录,原始数据作为初始过滤输入。- 每一步执行过滤器,拿到当前过滤器的剔除记录和过滤后的数据。
- 用
R.merge将新的剔除记录合并到累积对象中,同时把过滤后的数据传给下一个过滤器。 - 最终输出的数组第一个元素是所有分组的剔除ID列表,第二个元素是通过所有过滤的最终数据。
内容的提问来源于stack exchange,提问作者Andreas Herd
相关产品推荐
相关产品推荐

