jiku jiku - 6 months ago 21
Javascript Question

Filter by (unique) matching values

With Ramda and

const data = [{
"id": "a",
"name": "A"
}, {
"id": "b",
"name": "B"
}, {
"id": "c",
"name": "C"
}]


I can do

const findById = (id, data) => R.pipe(
R.find(R.propEq('id', id))
)(data)

const id = "a"

findById(id, data) // => { "id": "a", "name": "A" }


but what about taking an array of id values to return a list with just the matching objects? I.e.

const ids = ["a", "c"]

const findByIds = (ids, data) => R.pipe(
// ?
)(data)

findByIds(ids, data) // => [{"id": "a", "name": "A"}, {"id": "c", "name": "C"}]


Something like pluck, pick, etc, but for values instead of keys, where each value can be assumed unique.

(Preferring terse, maybe even point-free variants).

The closest I've gotten so far is exchanging the ? for either

R.filter(x => R.contains(x.id, ids))


or

R.takeWhile(x => R.contains(x.id, ids))


both yielding the A object.

Thanks! I'm pretty new to Ramda and the above is mostly how I use it, so any insights around that would be very welcome too.

UPDATE

This is a non-question. It actually works in the REPL but not for tests in my local env (Atom + Wallaby + AVA). Not sure why but I'll update if I figure it out. See verified answer for variations using both a static and dynamic key. Would still be fun to hear of any other approaches.

UPDATE 2

Turns out it was just a typo. Maybe I should reconsider using complex hashes for test ID's. :D

Answer

(Preferring terse, maybe even point-free variants).

This is the wrong objective. Prefer code that reads well and works. Coding is not a game where the shortest answer wins, except when coding is a game where the shortest answer wins. If you want "golfed" code, you should be asking there.

Anyway, you pretty much gave the answer yourself.

var data = [{
  "id": "a",
  "name": "A"
}, {
  "id": "b",
  "name": "B"
}, {
  "id": "c",
  "name": "C"
}];

const findByIds = ids=> R.filter(x=> R.contains(x.id, ids));

findByIds (['a', 'c']) (data);
//=> [{"id": "a", "name": "A"}, {"id": "c", "name": "C"}]

Maybe you'd like "id" to be a dynamic property

var data = [{
  "id": "a",
  "name": "A"
}, {
  "id": "b",
  "name": "B"
}, {
  "id": "c",
  "name": "C"
}];

const findBy = R.curry((prop,values)=> R.filter(x=> R.contains(x[prop], values)));

findBy ('id') (['a', 'c']) (data);
//=> [{"id": "a", "name": "A"}, {"id": "c", "name": "C"}]
Comments