【问题标题】:Use pipe filter functions with arguments in RamdaJS在 RamdaJS 中使用带参数的管道过滤器函数
【发布时间】:2019-07-10 18:54:15
【问题描述】:

假设我有这两个过滤器:

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 中为不同的过滤器函数应用参数。有可能吗?

【问题讨论】:

    标签: ramda.js


    【解决方案1】:

    您绝对可以使用 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 函数更简单,过滤谓词更简单,调用更明确。特别提高了nameStartsWith ('A')zipStartsWith ('8')的可读性

    【讨论】:

    • 是的,我同意。干净多了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-12-12
    • 1970-01-01
    • 2020-06-23
    • 2022-10-14
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2018-06-16
    相关资源
    最近更新 更多