2

If there is a Javascript object with multiple levels, as in:

myObject = {
        a: 12,
        obj11: {
                obj111: 'John',
                b:13,
                obj1111: { a:15, b: 35 } 
        },
        obj21: { 
                a:15,
                b:16 }
        }

I want to write a function to which is passed the object and an array of keys. The function should return a value based upon these keys. For example, passing [obj11,b] should return 13. Passing [obj11, obj1111,a] should return 15. Passing obj21 should return the object {a:15, b:16}

  function (myObj,myArr) {

      return keyVal;
  }

Assuming that the keys are always correct, can anyone help me solve this problem?

maracuja-juice
  • 994
  • 2
  • 14
  • 33
Sunny
  • 9,245
  • 10
  • 49
  • 79

3 Answers3

3

You can do this with a reduce() one-liner. Of course if you want to wrap it in a function, you can do that too.

var myObject = {
    a: 12,
   obj11: {
           obj111: 'John',
           b:13,
           obj1111: { a:15,
                      b: 35 }
           },
   obj21: {
           a:15,
           b:16 }
}

var arr =   ['obj11','b']
var val = arr.reduce((acc,curr) => acc[curr], myObject)
console.log(val)

var arr =   ['obj11','obj1111', 'b']
var val = arr.reduce((acc,curr) => acc[curr], myObject)
console.log(val)
Mark
  • 90,562
  • 7
  • 108
  • 148
  • `['obj11','obj1111', 'b', 'a', 'a']` will throw Error, returning undefined might be nicer. – Keith Oct 28 '17 at 20:42
  • Yup - I totally agree @Keith – Mark Oct 28 '17 at 20:43
  • @Mark_M Please see if you can help me with [this one](https://stackoverflow.com/questions/46994662/how-to-set-value-to-a-property-in-a-javascript-object-which-is-identified-by-an). Sounded simple when I read on reduce but am stuck. – Sunny Oct 28 '17 at 21:30
3

You could reduce the array with the keys and take an object as default value.

function getValue(object, path) {
    return path.reduce(function (r, k) {
        return (r || {})[k];
    }, object);
}

var object = { a: 12, obj11: { obj111: 'John', b: 13, obj1111: { a: 15, b: 35 }, obj21: { a: 15, b: 16 } } };

console.log(getValue(object, ['obj11', 'b']));
console.log(getValue(object, ['obj11', 'obj1111', 'a']));
console.log(getValue(object, ['obj11', 'obj21']));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Amazing! Thanks. I need to take a look at reduce. Can you save me some time to also have a setValue function. – Sunny Oct 28 '17 at 20:42
  • it's just the reverse function with taking the obejct and build an object if not set, at last assign the value. – Nina Scholz Oct 28 '17 at 20:48
  • I tried but I could not get it. The third argument to the function is the new value to be assigned. It is not exactly reverse of this function, I think. – Sunny Oct 28 '17 at 21:18
  • You could have a look here: [Change deeply nested key value of an object if there's an array of key names](https://stackoverflow.com/questions/43226800/change-deeply-nested-key-value-of-an-object-if-theres-an-array-of-key-names) – Nina Scholz Oct 29 '17 at 07:28
0

To increment the discussion, if you're using lodash you can also use the function _.get to get the value like this:

_.get(myObject, ['obj111', 'obj1111'])
//returns 'John'

If you object has properties with array values you can also get by indexes

var obj = {
        a: 1,
        b:[{
           d:4,
           c:8
        }]

_.get(obj, ['b','0','d'])
//returns 4

Source: https://lodash.com/docs/4.17.4#get

tiagolisalves
  • 503
  • 3
  • 9