5

Suppose I have a list of objects with many keys and I want to keep only certain keys from them. This is how I am doing it.

The Problem with other good solutions on SO are that if a key is not present in the keys to keep it still adds a key, value where the value is undefined.

let data = [{
   'a': 1,
   'b': 2,
   'c': 3
 }, 
 {
   'a': 1,
   'c': 3,
   'd': 4
 }]

const keys_to_keep = ['a', 'b']

data = data.map((obj) => {
  Object.keys(obj).forEach(function(key) {
    if(!keys_to_keep.includes(key))
      delete obj[key]
  });
  return obj;
})

Output :

[ { a: 1, b: 2 }, { a: 1} ]

Is there a better way to get this done. Any help is appreciated.

Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84
  • 4
    What problems are you having with the way you're doing it now? – Pointy Sep 09 '20 at 23:52
  • What is the expected output? – epascarello Sep 09 '20 at 23:55
  • https://stackoverflow.com/questions/54907549/keep-only-selected-keys-in-every-object-from-array – epascarello Sep 09 '20 at 23:57
  • 1
    If you happen to already be using lodash, see https://stackoverflow.com/questions/30726830/how-to-filter-keys-of-an-object-with-lodash – jarmod Sep 09 '20 at 23:59
  • @epascarello You can run the code on the SO link you shared with my data. It gives me `[ { a: 1, b: 2 }, { a: 1, b: undefined } ]`, whereas I wanted `[ { a: 1, b: 2 }, { a: 1} ]` . That is exactly what I have explained. – Akshay Hazari Oct 11 '20 at 04:15
  • @jarmod I can use lodash and run a foreach loop instead of includes. Is that what you are saying, the question is completely different. I some how got a notification of the msg now, something wrong with SO. This is a month old question. Sorry about that. – Akshay Hazari Oct 11 '20 at 04:19

2 Answers2

9

A couple of improvements.

  1. You're using .map() which creates a new array, but then you're just assigning it to the old variable. So, you apparently don't need to create a new array at all, you can just iterate the one you have and modify it.

  2. Put the properties you want to keep in a Set instead of an Array for potentially faster lookup.

  3. for/of loops are generally favored over .forEach() loops because of better flow control options (break, continue, return, etc...) and more opportunities for compiler optimization.

let kv = [{
   'a': 1,
   'b': 2,
   'c': 3
 }, 
 {
   'a': 1,
   'b': 2,
   'c': 3,
   'd': 4
 }]

const l = new Set(['a', 'b']);

for (let obj of kv) {
    for (let prop of Object.keys(obj)) {
       if (!l.has(prop)) {
           delete obj[prop];
       }
    }
}

console.log(kv);
jfriend00
  • 683,504
  • 96
  • 985
  • 979
3

You can use Object.fromEntries, after map and filter to keep only the relevant keys:

let data = [{'a': 1,'b': 2,'c': 3},{'a': 1,'c': 3,'d': 4}]
const keys_to_keep = ['a', 'b']

var result = data.map(obj =>
    Object.fromEntries(keys_to_keep.map(key => 
        obj.hasOwnProperty(key) && [key, obj[key]]
    ).filter(Boolean))
);

console.log(result);
trincot
  • 317,000
  • 35
  • 244
  • 286