在 RamdaJS 中使用带参数的管道过滤器函数
Use pipe filter functions with arguments in RamdaJS
假设我有这两个过滤器:
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
的参数是 J
。 getPersonsStartingWithZipCode
的参数是 4
如果我愿意 'manually' 我会这样:
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 函数使它更清晰一些。这是一种方法:
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')
的可读性
假设我有这两个过滤器:
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
的参数是 J
。 getPersonsStartingWithZipCode
的参数是 4
如果我愿意 'manually' 我会这样:
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 函数使它更清晰一些。这是一种方法:
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')