Joe
Joe

Reputation: 4254

Ramda, filter with or condition

let arr = [
  {
    name: 'Anna',
    q: {
      name: 'Jane'
    }
  }
];

const getName = R.prop('name');
const getQname = R.path(['q','name']);

A filter where any of these two functions passes.

Something like:

export const filterByName = (name) => 
R.filter(
  R.or(
   R.propEq(getName, name),
   R.propEq(getQname, name)
  )
)

Not working. How can I combine these two functions in a R.filter?

Upvotes: 2

Views: 1600

Answers (3)

Hitmands
Hitmands

Reputation: 14199

You could also write this in a point free style:

const nameIs = R.converge(R.or, [
  R.pathEq(['name']),
  R.pathEq(['q', 'name']),
]);

const onlyAnna = R.filter(nameIs('Anna'));
const onlyGiuseppe = R.filter(nameIs('Giuseppe'));

const data = [
  { name: 'Anna', q: { name: 'Jane' } },
  { name: 'Mark', q: { name: 'Mark' } },
  { name: 'Giuseppe', q: { name: 'Hitmands' } },
];

console.log('Anna', onlyAnna(data));
console.log('Giuseppe', onlyGiuseppe(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

Upvotes: 0

Ori Drori
Ori Drori

Reputation: 192422

Use R.either with R.propEq for the name and R.pathEq from q.name:

const filterByName = (name) =>
  R.filter(
    R.either(
      R.propEq('name', name),
      R.pathEq(['q', 'name'], name)
    )
  )

const arr = [{"name":"Anna","q":{"name":"Jane"}},{"name":"Smite","q":{"name":"Jane"}},{"name":"Another","q":{"name":"One"}}];

console.log(filterByName('Anna')(arr))
console.log(filterByName('Jane')(arr))
console.log(filterByName('XXX')(arr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

If you want to use an external function to extract the values, you can use R.pipe. Extract all property values with R.juxt, and then use R.any with R.equal to check for equality.

const getName = R.prop('name');
const getQname = R.path(['q','name']);

const filterByName = (name) =>
  R.filter(
    R.pipe(
      R.juxt([getName, getQname]), // get all names
      R.any(R.equals(name)) // check if any of the equals to name
    )
  )

const arr = [{"name":"Anna","q":{"name":"Jane"}},{"name":"Smite","q":{"name":"Jane"}},{"name":"Another","q":{"name":"One"}}];

console.log(filterByName('Anna')(arr))
console.log(filterByName('Jane')(arr))
console.log(filterByName('XXX')(arr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

Upvotes: 4

customcommander
customcommander

Reputation: 18941

I would use either as it works with functions:

export const filterByName = (name) => 
  R.filter(R.either(
   R.propEq('name', name),
   R.pathEq(['q', 'name'], name)));

or

const nameIs = R.propEq('name');
const qNameIs = R.pathEq(['q','name']);

export const filterByName = (name) => 
  R.filter(R.either(nameIs(name), qNameIs(name)));

Upvotes: 1

Related Questions