如何用Ramda的pipe实现嵌套数组的过滤与排序?
如何用Ramda的pipe实现过滤与排序功能?
需求场景
需要处理如下数组:
const items = [ { id: 1, subitems: [{name: 'Foo', price: 1000}]}, { id: 2, subitems: [{name: 'Bar'}]}, { id: 3, subitems: [{name: 'Foo', price: 500}]}, { id: 4, subitems: [{name: 'Qux'}]}, ]
要实现两个操作:
- 过滤出subitems中包含name为
Foo的元素的项 - 按
Foo的price进行排序(原始代码逻辑为降序,若需升序可调整)
原始JS实现如下:
const findFoo = value => value.name === 'Foo' items .filter(item => item.subitems.find(findFoo)) .sort((a, b) => a.subitems.find(findFoo).price > b.subitems.find(findFoo).price ? -1 : 1) // 原始注释预期结果:[{ id: 3, subitems: [...] }, { id: 1, subitems: [...] }]
问题分析
你尝试的Ramda代码返回空数组,核心问题是compose的执行顺序搞反了:
R.pipe( R.filter( R.compose( R.path(['subitems']), R.propEq('name', 'Foo') ) ), // Todo: sorting... )(items)
compose是从右到左执行的,这段代码会先对整个item执行R.propEq('name', 'Foo')(判断item自身的name是否为Foo,显然所有item都不满足,返回false),再对false执行R.path(['subitems'])得到undefined,最终过滤条件全为false,所以返回空数组。
正确实现
1. 修正过滤逻辑
需要先取item的subitems,再判断其中是否存在name为Foo的元素,用R.any替代find(find返回匹配项,存在即为truthy;any直接返回布尔值,逻辑等价):
R.filter(R.compose(R.any(R.propEq('name', 'Foo')), R.prop('subitems')))
2. 实现排序逻辑
用R.sort结合R.descend(生成降序比较器),先取出每个item中Foo的price,再按该值降序排列:
R.sort(R.descend(R.compose(R.prop('price'), R.find(R.propEq('name', 'Foo')), R.prop('subitems'))))
完整pipe代码
const result = R.pipe( // 过滤出包含Foo的项 R.filter(R.compose(R.any(R.propEq('name', 'Foo')), R.prop('subitems'))), // 按Foo的price降序排列 R.sort(R.descend(R.compose(R.prop('price'), R.find(R.propEq('name', 'Foo')), R.prop('subitems')))) )(items) console.log(result) // 输出:[{ id: 1, subitems: [{name: 'Foo', price: 1000}] }, { id: 3, subitems: [{name: 'Foo', price: 500}] }]
如果想要得到你注释中的升序结果(id3在前,id1在后),只需把R.descend换成R.ascend即可:
const resultAsc = R.pipe( R.filter(R.compose(R.any(R.propEq('name', 'Foo')), R.prop('subitems'))), R.sort(R.ascend(R.compose(R.prop('price'), R.find(R.propEq('name', 'Foo')), R.prop('subitems')))) )(items) console.log(resultAsc) // 输出:[{ id: 3, subitems: [{name: 'Foo', price: 500}] }, { id: 1, subitems: [{name: 'Foo', price: 1000}] }]
补充说明
R.compose:函数组合,从右到左执行,适合把多个单参数函数串联起来R.any:判断数组中是否有至少一个元素满足条件,等价于原生Array.someR.find:返回数组中第一个满足条件的元素,等价于原生Array.findR.descend/R.ascend:生成排序比较器,分别对应降序和升序,简化排序逻辑
内容的提问来源于stack exchange,提问作者fnx
相关产品推荐
相关产品推荐

