0

For example if we have an existing object

const mainObject = {
  title: 'some title',
  topics: {
    topic1: {
      path: '',
      id: 1
    },
    topic2: {
      path: '',
      id: 2
    }
  }
}

and I have a function that gets array containing keys for example

const arrayOfKeys = ['topics', 'topic1'];

function getObjectByKeys(arrayOfKeys) {
  // problem is length of the array may change
  const myObject = mainObject[arrayOfKeys[0]][arrayOfKeys[1]];
  return myObject;
}

function should return

{
      path: '',
      id: 1
}
  • What should be the expected object output for keys you mentioned? const arrayOfKeys = ['topics', 'topic1']; – Nitish Narang Oct 16 '18 at 12:03
  • 1
    You can loop over keys and/or values using `Object.keys()`, `Object.values()` and `Object.entries()`. But if every topic is going to be called topicX, with X being a numbers, might as well turn topics into an array so you can loop more easily. – Shilly Oct 16 '18 at 12:06
  • it could be called anything not topic necessarily –  Oct 16 '18 at 12:07
  • My point is, once you have a collection of things, whatever they are, it's mostly beneficial to make an array out of them so looping becomes very easy. – Shilly Oct 16 '18 at 12:09
  • Possible duplicate of [Access nested object dynamically by using array of string as a path](https://stackoverflow.com/questions/47550857/access-nested-object-dynamically-by-using-array-of-string-as-a-path) – str Oct 16 '18 at 12:13

6 Answers6

1

You can use .reduce here. Initialise the accumulator with the main object and on each iteration of its callback return the value corresponding to current key.

const mainObject = {
  title: 'some title',
  topics: {
    topic1: {
      path: '',
      id: 1
    },
    topic2: {
      path: '',
      id: 2
    }
  }
}

const arrayOfKeys = ['topics', 'topic1'];

function getObjectByKeys(arrayOfKeys) {
  return arrayOfKeys.reduce((a, el, i, arr) => {
    return a[el] || {};    
  }, mainObject);
}

console.log(getObjectByKeys(arrayOfKeys));
void
  • 36,090
  • 8
  • 62
  • 107
0

One possible solution could be using the forEach loop.

const mainObject = { title: 'some title', topics: { topic1: { path: '', id: 1 }, topic2: { path: '', id: 2 } } }
const arrayOfKeys = ['topics', 'topic1'];

function getObjectByKeys(arrayOfKeys) {
  let result = Object.assign({}, mainObject);
  arrayOfKeys.forEach(function(key){
    result = result[key];
  });
  return result;
}

console.log(getObjectByKeys(arrayOfKeys));

Another approach is to use reduce method by passing a callback function as argument.

const mainObject = { title: 'some title', topics: { topic1: { path: '', id: 1 }, topic2: { path: '', id: 2 } } }
const arrayOfKeys = ['topics', 'topic1'];

getObjectByKeys = (arrayOfKeys) => {
  return arrayOfKeys.reduce((obj, item) => obj[item], mainObject);
}

console.log(getObjectByKeys(arrayOfKeys));
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
0

You can use reduce()

const mainObject = {
  title: 'some title',
  topics: {
    topic1: {
      path: '',
      id: 1
    },
    topic2: {
      path: '',
      id: 2
    }
  }
};
const arrayOfKeys = ['topics', 'topic1'];

var aa= arrayOfKeys.reduce((carry,value,index)=>{
             return carry[value];
        },mainObject);
        
console.log(aa);
Mithu CN
  • 605
  • 5
  • 11
0

you can use recursive.

const mainObject = {
  title: 'some title',
  topics: {
    topic1: {
      path: '',
      id: 1
    },
    topic2: {
      path: '',
      id: 2
    },
    topic3: {
      path: 'more depth',
      subtopic: {
        path: '',
        id: 4
      },
      id: 3
    }
  }
}

const arrayOfKeys = ['topics', 'topic3', 'subtopic'];

function getObjectByKeys(arrayOfKeys, currentObj, index = 0) {
  if(index >= arrayOfKeys.length) {
    return currentObj;
  }
  return getObjectByKeys(arrayOfKeys, currentObj[arrayOfKeys[index]], index+1)
}

console.log(getObjectByKeys(arrayOfKeys, mainObject));
wang
  • 1,660
  • 9
  • 20
0

you can edit your function as below and it will give you desired output.

function getObjectByKeys(obj, [first, ...rest]) {
  if(rest.length > 0 ) return getObjectByKeys(obj[first], rest) 
  else return obj[first]
}

getObjectByKeys(mainObject, ['topics', 'topic1'])
Nitish Narang
  • 4,124
  • 2
  • 15
  • 22
0

I would change topics into an array so finding any element becomes trivial. The code is almost human readable now: "find entry with id 1 inside field_name of mainObject."

const mainObject = {
  title: 'some title',
  topics: [
    { id: 1, path: 'first' },
    { id: 2, path: 'second' }
  ]
};
const field_name = 'topics';
const entry_to_find = 1;

const entry = mainObject[ field_name ].find( entry => entry.id === entry_to_find );
console.log( entry );
Shilly
  • 8,511
  • 1
  • 18
  • 24