Reputation: 14816
I'm using Ramda as my functional programming helper library to build a React app.
I'm trying to build myself whereAny
. Ramda exposes where
which checks if every prop it is given satisfies the respective predicate.
I want to build a function that accepts an array of keys, an object and a search term and if any of the keys (which values are strings) includes the search term it should return true
. If not it should return false
.
Here is my current workaround:
export const whereAny = keys => obj => searchTerm =>
R.any(
R.pipe(
R.toLower,
R.includes(R.toLower(searchTerm))
),
R.values(R.pick(keys, obj))
);
export const contactNameIncludesSearchValue = whereAny(['firstName', 'lastName']);
As you can see I use it to see if some values of a contact include the search term (IRL I use more than just firstName
and lastName
).
My question is how can you build such a whereAny
function? I looked into the Ramda cookbook and on Google and couldn't find a recipe for whereAny
.
The problem with my workaround (apart from the fact that it's probably not optimal) is that you can't specify different functions just like in where
. So ideally my api would look like this:
const pred = searchValue => R.whereAny({
a: R.includes(searchValue),
b: R.equals(searchValue),
x: R.gt(R.__, 3),
y: R.lt(R.__, 3)
});
Upvotes: 2
Views: 308
Reputation: 7505
Old question, but Ramda has recently released whereAny
.
The docs are at https://ramdajs.com/docs/#whereAny
Upvotes: 1
Reputation: 74234
Here's what I would do:
const fromPair = R.apply(R.objOf);
const whereFromPair = R.compose(R.where, fromPair);
const whereAny = R.compose(R.anyPass, R.map(whereFromPair), R.toPairs);
Just tested it and it works.
Upvotes: 2
Reputation: 50807
I would probably use the answer from Aadit M Shah, but you might also model it on the implementation of where
const whereAny = R.curry((spec, testObj) => {
for (let [key, fn] of Object.entries(spec)) {
if (fn(testObj[key])) {return true}
}
return false
})
const pred = searchValue => whereAny({
a: R.includes(searchValue),
b: R.equals(searchValue),
x: R.gt(R.__, 3),
y: R.lt(R.__, 3)
});
console.log(pred("hello")({ a: [], b: "hola", x: 3, y: 2 }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Upvotes: 2
Reputation: 18941
I think you should curry your functions using Ramda's curry
.
Why?
With this form of currying, you have to call it this way and this way only:
const abc = a => b => c => a + b + c;
abc(1)(2)(3); // 6
Whereas with this form you are more flexible:
const abc = curry((a, b, c) => a + b + c);
abc(1, 2, 3); // 6
abc(1, 2)(3); // 6
abc(1)(2)(3); // 6
Also note that Ramda functions tend to accept the data it operates on as the last parameter:
Ramda functions are automatically curried. This allows you to easily build up new functions from old ones simply by not supplying the final parameters.
The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last.
The last two points together make it very easy to build functions as sequences of simpler functions, each of which transforms the data and passes it along to the next. Ramda is designed to support this style of coding.
I think we can still use this approach to solve your problem:
const whereAny = curry((keys, search, obj) =>
compose(includes(search), props(keys))
(obj));
const whereNameIsFoo = whereAny(['firstName', 'lastName'], 'foo');
console.log(whereNameIsFoo({firstName: 'john', lastName: 'foo'}));
console.log(whereNameIsFoo({firstName: 'bar', lastName: 'baz'}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {curry, compose, flip, includes, props} = R;</script>
Upvotes: 2