0
const people = [
  {
    name: 'bill',
    age: 52
  },
  {
    name: 'james',
    age: 27
  },
  {
    name: 'james',
    age: 17
  }
]

const newPeople = R.reject(person => {
  return R.includes('jam', person.name)
})(people)

Is there a more elegant Ramda way to write this? I am looking to return an array that removes all people objects that have the string jam in their name.

Perhaps something like R.reject(R.where(...)) ?

Thanks!

skålfyfan
  • 4,931
  • 5
  • 41
  • 59

2 Answers2

4

I think you were on the right track with where.

This reads quite well to me:

const jamless = reject (where ({name: includes ('jam')}))

const people = [{name: 'bill', age: 52}, {name: 'james', age: 27}, {name: 'james', age: 17}]

console .log (
  jamless (people)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script> const {reject, where, includes} = R                 </script>

Reading the keywords aloud, we can hear "reject where name includes 'jam'", not a bad English description of the problem.

If you want to parameterize this, it could just be

const disallow = (str) => reject (where ({name: includes(str)}) )
const jamless = disallow ('jam')

(Although I'm quite sure we could make a point-free version of disallow, I see no reason to try, as this is already quite readable.)

See also the related answer, https://stackoverflow.com/a/29256202

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • maybe show that `name` can easily be parameterized too? – Mulan Aug 29 '19 at 18:57
  • 1
    @user633183: Sure, `const disallow = (prop) => (val) => reject (where ({[prop]: includes(val)}) )`, but somewhere you need to get back to the generic usage of `where` too; this is starting to push the boundaries for me. – Scott Sauyet Aug 29 '19 at 19:16
  • Yep. I ended up with `R.reject(R.where({ name: R.includes('jam') }));` which is exactly what you proposed here. Always nice to get a response from Ramda developer! :) Thanks. – skålfyfan Aug 30 '19 at 17:15
1

I would break this down into smaller functions:

withJam

Returns true if a string contains the string jam (case insensitive)

const withJam = R.test(/jam/i);
withJam('Bill') //=> false
withJam('James') //=> true

nameWithJam

Returns true if a property contains the string jam (case insensitive)

const nameWithJam = R.propSatisfies(withJam, 'name');
nameWithJam({name: 'Bill'}) //=> false
nameWithJam({name: 'James'}) //=> true

Then you can write:

R.reject(nameWithJam)(people)

I think that your initial solution is good enough already. I just made it pointfree, i.e. without mentioning the parameters explicitly.

Example:

Let's say that you need a function that adds 5 to any number:

const add5 = n => n + 5;
add5(37) //=> 42

You could get rid of n if you could work with a curried version of add. Let's define add first:

const add = m => n => m + n;

Then let's create add5:

const add5 = add(5);
add5(37) //=> 42

You can replace this:

[1,2,3].map(n => n + 5) //=> [6,7,8]

With:

[1,2,3].map(add(5)) //=> [6,7,8]

⚠️ Pointfree style is certainly interesting and worth exploring. But it can also unnecessarily complicate things :) See When is it appropriate to choose point-free style vs a data-centric style in functional programming?

customcommander
  • 17,580
  • 5
  • 58
  • 84
  • There's absolutely nothing wrong with this approach, and it's a well-written answer (upvoted!) But I think my answer shows a cleaner implementation. – Scott Sauyet Aug 29 '19 at 17:14
  • Agreed. I rarely think of using where. Nice! – customcommander Aug 29 '19 at 17:33
  • `where` was featured in the [very first article](http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda) written about Ramda, more than five years ago. And I still sometimes forget about it. – Scott Sauyet Aug 29 '19 at 17:41