2

I want to pass a function an array of keys and an object, and return a new object that only contains the key/value pairs that I specify in the keys array.

So if I had an object like this:

{"name" : "John Smith", "position" : "CEO", "year" : "2019" }

And I passed the array

["name", "year"]

the new object returned would be:

{"name" : "John Smith", "year" : "2019" }

I've been playing around with it, but my code is not working.

function parse(keys, data) {
    let obj = JSON.parse(data);

    let newObj = {};

    keys.array.forEach(element => {
        newObj[element] = obj.element;
    });

    return newObj;
};
trincot
  • 317,000
  • 35
  • 244
  • 286
CastleCorp
  • 55
  • 1
  • 1
  • 11
  • 1
    Please read the description of the `json` tag. This question is not about JSON, but about a JavaScript object. That it is the result of applying `JSON.parse` is not relevant. – trincot Jun 27 '19 at 17:56
  • Thanks, I removed the tag. – CastleCorp Jun 27 '19 at 17:59
  • I also removed the word from your question. You can just say "object" instead of the misleading "JSON object". JSON is a text format. – trincot Jun 27 '19 at 18:00
  • 1
    `obj.element;` should be `obj[element]` – nem035 Jun 27 '19 at 18:00
  • Possible duplicate of [How to filter an array from all elements of another array](https://stackoverflow.com/questions/34901593/how-to-filter-an-array-from-all-elements-of-another-array) – DCR Jun 27 '19 at 18:06

9 Answers9

3

You dont need to do parse.Secondly this line keys.array.forEach is wrong. This is because there is no array key inside keys.Also replace obj.element; with data[element]

let data = {
  "name": "John Smith",
  "position": "CEO",
  "year": "2019"
}
let keys = ["name", "year"]


function parse(keys, data) {
  let newJson = {};
  keys.forEach(element => {
    newJson[element] = data[element];
  });

  return newJson;
};

console.log(parse(keys, data))
brk
  • 48,835
  • 10
  • 56
  • 78
2

One way to achieve this would be through filtering an array of object entries:

const entries = Object.entries({
  "name" : "John Smith",
  "position" : "CEO",
  "year" : "2019"
})

entries contains:

[
  [
    "name",
    "John Smith"
  ],
  [
    "position",
    "CEO"
  ],
  [
    "year",
    "2019"
  ]
]

Filtering out keys:

const filteredEntries = entries.filter(([ key ]) => ["name", "year"].includes(key))

filteredEntries contains:

[
  [
    "name",
    "John Smith"
  ],
  [
    "year",
    "2019"
  ]
]

Last step - construct an object:

const filteredObject = Object.fromEntries(filteredEntries)

filteredObject contains:

{
  "name": "John Smith",
  "year": "2019"
}

Putting it together as a function:

function filterObjectByGivenKeys(object, keys) {
  const filteredEntries = Object
    .entries(object)
    .filter(([ key ]) => keys.includes(key))

  return Object.fromEntries(filteredEntries)
}

Or, if we prefer reduce and more terse syntax:

const filterObjectByGivenKeys = (object, keys) =>
  Object.entries(object)
    .filter(([ key ]) => keys.includes(key))
    .reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {})
Pa Ye
  • 1,779
  • 12
  • 22
  • 1
    Actually, an one-liner `Object.fromEntries(Object.entries(o).filter(e => keys.includes(e[0])))` – georg Jun 27 '19 at 18:33
2

The correct (e.g., lazy) way to accomplish this would to use lodash, because code you don't write is code you don't have to maintain:

const pick = require('lodash.pick');

const obj = {
    name     : 'John Smith' ,
    position : 'CEO' ,
    year     : '2019',
};
const desired = [ 'name', 'year' ];

const filtered = pick(obj, desired );

If you want to roll your own, something like this should do the trick:

function filter_obj(obj = {}, keys = [] ) {
    if ( !keys || !keys.length ) return obj;

    const desired = new Set(keys);
    const filtered = {};
    for ( [ key, value ] of Object.entries(obj) ) {
        if ( !desired.has(key) ) continue;
        filtered[key] = value;
    }
    return filtered;
}
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
1

I think your code is close.

Maybe try:

newObj[element] = obj[element];

instead of

newObj[element] = obj.element

That way you will use the variable element instead of trying to look up the key "element" which will return undefined.

Dustin Michels
  • 2,951
  • 2
  • 19
  • 31
0

To achieve expected result, use below option of using for in to loop object keys

  1. Loop keys by for in
  2. Check key with the filtered keys
  3. Add to new object

var obj = {"name" : "John Smith", "position" : "CEO", "year" : "2019" }
var fil = ["name", "year"]
var result = {}
for(let key in obj){
  if(fil.indexOf(key) !==-1){
    result[key] = obj[key]
  }
}

console.log(result)
Naga Sai A
  • 10,771
  • 1
  • 21
  • 40
0

Another option is to use the reduce method:

var input = {"name" : "John Smith", "position" : "CEO", "year" : "2019" };
var properties = ["name", "year"];

function getNewObject(json, props) {
  // Get all object properties
  var availableProperties = Object.keys(json);

  // Loop through the requested properties and return the object
  return props.reduce((pv, cv) => {
    // Check if the property exists on the object
    if(availableProperties.includes(cv)){
      pv[cv] = json[cv]
    }
    return pv;
  }, {});
}

console.log(getNewObject(input, properties));
Stefan Koenen
  • 2,289
  • 2
  • 20
  • 32
0

I have removed the object parsing you had above since your object isn't stringified... If it was stringified the "" would be wrapping the entire object... in production you can simple add in the parsing if needed.

function parse(keys, data) {
   let newObj = {};

   for (const dataKey in data){
       for (let i = keys.length - 1; i >= 0; i--) {
           if (data.hasOwnProperty(keys[i])) {
               newObj[keys[i]] = data[keys[i]];
           }
       }
   }

   return newObj;
};
Michael Paccione
  • 2,467
  • 6
  • 39
  • 74
0

you do that using filter and Object entries or you can also use reduce.

const person = {
  "name": "John Smith",
  "position": "CEO",
  "year": "2019",
  "job": "front-end"
};

const formatObject = (arr, o) => {
  let finalObject = {};

  Object.entries(o).filter(([key, value]) => {
    if (arr.includes(key)) {
      finalObject = {
        ...finalObject,
        [key]: value
      }
    }

  });

  return finalObject;

}


console.log(formatObject(["name", "year", "job"], person))
Aziz.G
  • 3,599
  • 2
  • 17
  • 35
0

First add this line {"name" : "John Smith", "position" : "CEO", "year" : "2019" } inside single quotation, or you don't need to use JSON.parse:

'{"name" : "John Smith", "position" : "CEO", "year" : "2019" }'

Then you don't need the array, only keys, keys.array.forEach. And obj[element]:

  keys.forEach(element => {
    newObj[element] = obj[element];
  });