Reputation: 3593
I want to make a function that, given a list of predicates, produces an array filter.
Using lodash, I define:
const { curryRight, filter, flowRight } = require('lodash');
const curriedFilter = curryRight(filter);
const filterFromPredicates = (predicateList) => flowRight(...predicateList.map(curriedFilter));
But this gives the wrong answer:
const filter = filterFromPredicates([(x) => x > 2, (x) => x > 4])
filter([1,2,3,4,5,6,7,8,9]) // -> [1,2,3,4,5,6,7,8,9]
where I would expect [5,6,7,8,9]
However defining the curried filter as follows works:
const curriedFilter = (predicate) => (array) => array.filter(predicate);
Am I misunderstanding the usage of curryRight
?
Upvotes: 4
Views: 504
Reputation: 191976
Your code doesn't work because the map passes 3 arguments to the curriedFilter
- the predicate, the index, and the original array. You'll need to pass only the predicate to curriedFilter
.
const { curryRight, filter, flow, ary } = _;
const curriedFilter = ary(curryRight(filter), 1);
const filterFromPredicates = (predicateList) => flow(...predicateList.map(curriedFilter)); // limit the number of params passed to curriedFilter
const fn = filterFromPredicates([x => x > 2, x => x < 6]); // don't override the filter you've imported
const result = fn([1,2,3,4,5,6,7,8,9]); // -> [3, 4, 5]
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Another option would be to limit the number of parameters curriedFilter
accepts with _.ary()
:
const { curryRight, filter, flow, ary } = _;
const curriedFilter = ary(curryRight(filter), 1);
const filterFromPredicates = (predicateList) => flow(...predicateList.map(curriedFilter)); // limit the number of params passed to curriedFilter
const fn = filterFromPredicates([x => x > 2, x => x < 6]); // don't override the filter you've imported
const result = fn([1,2,3,4,5,6,7,8,9]); // -> [3, 4, 5]
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
You can use _.overEvery()
to generate the predicate you'll pass to the curried filter:
const { flow, overEvery, curryRight, filter } = _;
const filterFromPredicates = flow(overEvery, curryRight(filter));
const fn = filterFromPredicates(x => x > 2, x => x < 6); // don't override the filter you've imported
const result = fn([1,2,3,4,5,6,7,8,9]); // -> [3, 4, 5]
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
If you use lodash/fp you want need the _.curryRight()
since the functions are auto-curried, and the parameters are iteratee-first data-last:
const { flow, overEvery, filter } = _;
const filterFromPredicates = flow(overEvery, filter);
const fn = filterFromPredicates([x => x > 2, x => x < 6]); // don't override the filter you've imported
const result = fn([1,2,3,4,5,6,7,8,9]); // -> [3, 4, 5]
console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
Upvotes: 3
Reputation: 4488
How about this:
function filterFromPredicates(predicates) {
return (...args) => predicates
.map(predfn=> predfn(...args))
.every(a=>a)
}
[1,2,3,4,5,6,7,8,9].filter(filterFromPredicates([(x) => x > 2, (x) => x > 4]))
if you want everything in the same function then :
function filterFromPredicates(predicates) {
return (someArray)=> someArray.filter((...args) => predicates
.map(predfn=> predfn(...args))
.every(a=>a))
}
const filter = filterFromPredicates([(x) => x > 2, (x) => x > 4])
filter([1,2,3,4,5,6,7,8,9])
That will return as you wanted ^
Upvotes: 1