简体   繁体   中英

Filter object base on an array with Ramda.js

let obj = {
  tom: {
    id: 0
  },
  david: {
    id: 1
  },
  john: {
    id: 2
  }
}

let ids = [1, 2]

I want to filter the obj based on ids.

The result I want is

{ david: { id: 1 }, john: { id: 2 } }

Because ids above is [1, 2].

I want to do this with Ramda.js.

Plase help me.


Ok, I'm sorry.

I did something like this.

let obj2 = {}
ids.forEach((x) => {
      obj2 += R.filter(y => y.id === x, obj)
      })
obj = obj2

But, it is not correct.

And I don't want to use forEach.

I want to do with Ramda.js .

You can do this only using Javascript , first you can create a set with the ids you want to keep (check if set has an element is O(1) ). Then, you can loop on the original object and add the key with his value on a new object if the set has the related id :

 let obj = { tom: {id: 0}, david: {id: 1}, john: {id: 2} } let ids = [1, 2]; const filterByIds = (obj, ids) => { let idsSet = new Set(ids); let filteredObj = {}; for (k in obj) { if (idsSet.has(obj[k].id)) filteredObj[k] = obj[k]; } return filteredObj; } console.log(filterByIds(obj, ids)); 
 .as-console {background-color:black !important; color:lime;} .as-console-wrapper {max-height:100% !important; top:0;} 


Update to use Ramda:

With Ramda you can do like this:

 let obj = { tom: {id: 0}, david: {id: 1}, john: {id: 2} } let ids = [1, 2]; let idsSet = new Set(ids); const hasValidId = o => idsSet.has(o.id); let res = R.filter(hasValidId, obj); console.log(res); 
 .as-console {background-color:black !important; color:lime;} .as-console-wrapper {max-height:100% !important; top:0;} 
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script> 

Easy if you read the documentation here

You can do it in pure JavaScript by using Object.entries and destructuring with includes like so:

 let obj = { tom: { id: 0 }, david: { id: 1 }, john: { id: 2 } }; let ids = [1, 2]; let result = {}; Object.entries(obj).forEach(([name, { id }]) => { if (ids.includes(id)) { result[name] = { id: id }; } }); console.log(result); 

Generally speaking, you should strive to work with data structures that help you rather than work against you.

With a simplified data structure such as this one below:

const obj = [
  {id: 0, name: 'tom'},
  {id: 1, name: 'david'},
  {id: 2, name: 'john'}
]

You could use innerJoin :

innerJoin((cur, id) => cur.id === id, obj, [1, 2])

How to convert your original data structure into a simplified one?

It can be a two-step process with Ramda:

  1. Split your object into an array of key/value pairs with toPairs :

     {tom:{id:0}} ~> [['tom', {id: 0}]] 
  2. Map each pair into an object:

     [['tom', {id: 0}]] ~> [{name: 'tom', id: 0}] 

 const obj = { tom: { id: 0 }, david: { id: 1 }, john: { id: 2 } } const convert = R.compose(R.map(([name, id]) => ({name, ...id})), R.toPairs); console.log(convert(obj)) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script> 

Try This:

 let obj = { tom: { id: 0 }, david: { id: 1}, john: {id: 2} } let ids = [1, 2] ; let result = {} ; for ( var o in obj ) { if (ids.includes(obj[o].id)) result[o] = obj[o]; } console.log(result) ; 

Unless this is an exercise in learning Ramda, beware of the idea of wanting to do this in Ramda. I'm one of the primary authors of Ramda, and a big fan, but I need to stress that it's simply a toolkit than can help in some situations. When it helps, great, but it shouldn't be a goal.

Now, I do think it can help here. This is what I would do with Ramda:

 const matchIds = (obj, ids) => filter(propSatisfies(includes(__, ids), 'id'), obj) let obj = {tom: {id: 0}, david: {id: 1}, john: {id: 2}} let ids = [1, 2] console.log(matchIds(obj, ids)) 
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script> const {__, filter, propSatisfies, includes} = R </script> 

An alternative, especially if the list of ids is less likely to change than the object, is this:

 const matchIds = (ids) => filter(propSatisfies(includes(__, ids), 'id')) let obj = {tom: {id: 0}, david: {id: 1}, john: {id: 2}} let ids = [1, 2] console.log(matchIds(ids)(obj)) 
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script> const {__, filter, propSatisfies, includes} = R </script> 

There are some reasons not to like the placeholder (' __ '). If you feel that way, you can replace includes(__, ids) with flip(includes)(ids) .

Update

I don't take my own advice here. While I still would use Ramda for the filter , there is no need for propSatisfies here. A simple lambda would be perfectly fine:

const matchIds = (ids) => filter(({id}) => ids.includes(id))

This is much cleaner and more readable, at least once you're used to the Ramda norm of partial application. ( filter takes two arguments: the predicate function and the object to filter with it. Since we only supply the first, this gives us back a function expecting the second. When we call that resulting function with the object, the filtering happens.)

The reason I would still use Ramda's filter is that there is no direct built-in version of it as applied to objects. Ramda supplies a simple alternative to writing a one-off object filtering.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM