SwishAllDay
SwishAllDay

Reputation: 11

How to traverse a nested object based on a path in an array in javascript?

const obj = { 
    first: { second: { third: 'done'} },
    hello: { world: { foo: { bar: 'wrong' } } },
    second: { third: 'wrong'}
};

const arr = [ 'first', 'second', 'third' ];

function traverse(obj, arr) {
    
}
// output = 'done'

Given a first input as a nested object, and a second input as an array containing strings, what is the best way to traverse the nested object based on the path set by the array to output done?

Upvotes: 1

Views: 825

Answers (3)

Simon Dehaut
Simon Dehaut

Reputation: 2661

if you want it short and to handle system file path like :

it returns the object if exist and -1 if not

const obj = { 
    first: { second: { third: 'done'} },
    hello: { world: { foo: { bar: 'wrong' } } },
    second: { third: 'wrong'}
};

function traverse(obj, path) {
    let seq = path.split('/').filter(x => x != '');
    seq.map( s => obj = !obj[s] ? -1 : obj[s] );
    return obj;
}
console.log(traverse(obj, '/hello/notexist/'));
console.log(traverse(obj, '/hello/world/'));

or even shorter with a reduce() instead of a map() :

function traverse(obj, path) {
    let seq = path.split('/').filter(x => x != '');
    return seq.reduce((acc, curr) => !acc[curr] ? -1 : acc[curr], obj);
}

or a even even shorter :

 function traverse(obj, path) {
      return path
      	.split('/')
        .filter(Boolean)
        .reduce((acc, curr) => acc[curr] ? acc[curr] : -1, obj);
}
    
const obj = { 
        first: { second: { third: 'done'} },
        hello: { world: { foo: { bar: 'wrong' } } },
        second: { third: 'wrong'}
};

const res = traverse(obj, '/hello/world/'); // return {foo:...}
console.log(res);

Upvotes: 0

slider
slider

Reputation: 12990

You can reduce the array arr, changing the accumulator to a deeper object at each step.

const obj = { 
  first: { second: { third: 'done'} },
  hello: { world: { foo: { bar: 'wrong' } } },
  second: { third: 'wrong'}
};
const arr = [ 'first', 'second', 'third' ];

function traverse(obj, arr) {
  return arr.reduce((acc, curr) => acc ? acc[curr] : undefined, obj);
}

console.log(traverse(obj, arr));
console.log(traverse(obj, ['hello', 'world', 'foo']));
console.log(traverse(obj, ['first', 'hello', 'world']));

Upvotes: 2

Code Maniac
Code Maniac

Reputation: 37755

You can use references

  • Loop over the array untill the last second last element
  • If the ref[key] is an object, change ref to ref[key]
  • else return Not Found
  • Check if the ref has property name same as last variable then return ref[last] else return Not Found

const obj = { first: { second: { third: 'done'} },hello: { world: { foo: { bar: 'wrong' } } },second: { third: 'wrong'}};
const arr = [ 'first', 'second', 'third' ];

function traverse(obj, arr) {
  let ref = obj
  let last = arr[arr.length-1]
  for(let i=0; i<arr.length-1; i++){
    let key = arr[i]
    if(typeof ref[key] === 'object'){
      ref = ref[key]
    } else{
      return "Not found"
    }
  }
  return ref.hasOwnProperty(last) ? ref[last] : "Not found"
}

console.log(traverse(obj,arr))
console.log(traverse(obj,['first','third']))
console.log(traverse(obj,['hello','world']))

Upvotes: 0

Related Questions