在RamdaJS中将管道过滤器函数与参数一起使用

时间:2019-07-03 16:52:20

标签: ramda.js

说我有这两个过滤器:

const getNamesStartingWith = (letter) => persons => {
  return persons.filter(person => person.name.startsWith(letter);  
}

const getPersonsStartingWithZipCode = (zipCode) => persons => {
  return persons.filter(person => person.address.zipCode.startsWith(zipCode);
}

我想制作一个通用管道过滤器。

const pipeFilter = (funcArr, args) => arr => {
...
}

funcArr是要运行的函数的数组。 args是一个双精度数组,其中索引是函数的参数。

因此,在我的示例函数中,它将是:

const pipeFilter = ([getNamesStartingWith, getPersonsStartingWithZipCode], [['J'], [4]]) => persons => {..}

getNamesStartingWith的参数为JgetPersonsStartingWithZipCode的参数为4

如果我要“手动”操作,我会选择类似的东西:

export const doPipeFiltering = (funcArr: any[], args: any[]) => (arr) => {

  return funcArr.reduce((acc, func, index) => {

    let filterdArr;
    if (index === 0) {
      filterdArr = func(...args[index])(arr);
    } else {
      filterdArr = func(...args[index])(acc);
    }
    acc = filterdArr;
    return acc;
  }, []);
};

工作。但是我想在RamdaJs中做到这一点,所以我可以在那里使用所有简洁的函数。

我找不到如何在Ramda中为差异过滤器函数应用参数。有可能吗?

1 个答案:

答案 0 :(得分:2)

使用Ramda函数,您绝对可以使它更干净。这是一种方法:

const doPipeFiltering = curry ( (funcArr, args, arr) => 
  reduce ( (acc, func) => func (acc), arr, zipWith (apply, funcArr, args) ))

const getNamesStartingWith = (letter) => (persons) => {
  return persons.filter(person => person.name.startsWith(letter)) 
}

const getPersonsStartingWithZipCode = (zipCode) => persons => {
  return persons.filter(person => person.address.zipCode.startsWith(zipCode))
}
                      
const people = [
  {name: 'Amanda', address: {zipCode: '86753'}}, 
  {name: 'Aaron', address: {zipCode: '09867'}},
  {name: 'Amelia', address: {zipCode: '85309'}}, 
  {name: 'Bob', address: {zipCode: '67530'}}
]

console .log (
  doPipeFiltering (
    [getNamesStartingWith, getPersonsStartingWithZipCode], 
    [['A'], ['8']],
    people
  )
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {curry, reduce, zipWith, apply} = R                    </script>

但是我建议这不是一个非常符合人体工程学的API。首先,如果过滤功能具有完全通用的接口,它可能还不错,但是现在您必须提供两个单独的数组参数,它们的值必须同步。对我来说,这是灾难的秘诀。

第二,为此我们需要创建的是过滤列表的函数。如果代码处理了过滤,我会发现它更加干净,我们只提供了一组简单的谓词。

对于我认为更清洁的API,这是另一种建议:

const runFilters = useWith (filter, [allPass, identity] )

// or one of these
// const runFilter = curry((filters, xs) => filter(allPass(filters), xs))
// const runFilters = curry ((filters, xs) => reduce ((a, f) => filter (f, a), xs, filters))

const nameStartsWith = (letter) => (person) => person.name.startsWith (letter)
const zipStartsWith = (digits) => (person) => person.address.zipCode.startsWith (digits)

const myFilter = runFilters ([nameStartsWith ('A'), zipStartsWith ('8')])

const people = [
  {name: 'Amanda', address: {zipCode: '86753'}}, 
  {name: 'Aaron', address: {zipCode: '09867'}},
  {name: 'Amelia', address: {zipCode: '85309'}}, 
  {name: 'Bob', address: {zipCode: '67530'}}
]

console .log (
  myFilter (people)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {useWith, filter, allPass, identity} = R               </script>

请注意,这里的main函数更简单,filter谓词更简单,并且调用更加明确。 nameStartsWith ('A')zipStartsWith ('8')

的可读性特别提高