DEV Community

Aastha Talwaria
Aastha Talwaria

Posted on

Find Value at Key

Problem Statement:

  • Write method findPath
  • Should take two params:
    • object
    • keys separated by dots as string
  • Return value if it exists at that path inside the object, else return undefined

My Approach:

  • Initialise answerObject as the original Object.
  • Split the string with ..
  • Traverse the spitted array.
    • Update answerObject with the value read from iterated key.
    • If answerObject is not undefined, then continue.
    • Else break.
  • Return answerObject.

CODE:

var obj = {
    a: {
        b: {
            c: 12,
            j: false
        },
        k: null
    }
};

function findPath(obj, str=''){
    var ansObj = JSON.parse(JSON.stringify(obj));
    var attributes = str.split('.');
    if(!attributes.length){
        return undefined;
    }
    let index = 0;
    while(attributes[index]){
        if(ansObj[attributes[index]]!== undefined){
            ansObj = ansObj[attributes[index]];
        } else {
            ansObj = undefined;
            break;
        }
        index++;
    }
    return ansObj;
}
//Output: 
console.log(findPath(obj, 'a.b.c')); // 12
console.log(findPath(obj, 'a.b')); // {c: 12, j: false}
console.log(findPath(obj, 'a.b.d')); // undefined
Enter fullscreen mode Exit fullscreen mode

Let's discuss your approach in the discussion box or you can hit me up at aastha.talwaria29@gmail.com.

Thanks for reading.

Discussion (4)

Collapse
darkwiiplayer profile image

I shortened it a little bit :D

const deepIndex = (obj, next, ...rest) => next ? obj ? deepIndex(obj[next], ...rest) : undefined : obj
const findPath = (obj, path) => deepIndex(obj, path.split("."))
Enter fullscreen mode Exit fullscreen mode

Or alternatively:

let deepIndex = (obj, ...path) => path.reduce((obj, index) => obj ? obj[index] : undefined, obj)
Enter fullscreen mode Exit fullscreen mode
Collapse
frankwisniewski profile image
Frank Wisniewski

I don't understand why you need that.
a simple:

console.log(obj.a.b.c)
Enter fullscreen mode Exit fullscreen mode

gives the same result.

Collapse
peerreynders profile image
peerreynders

When you are dealing with data where the contents may vary and you don't want to necessarily run into Uncaught TypeError: Cannot read properties of undefined

If the path is fixed at design time in modern JavaScript you can use the Optional chaining (?.) and Nullish coalescing operator (??) operator to avoid errors.

const text = '{"a":{"b":{"c":12,"j":false},"k":null}}';
const data = JSON.parse(text);

console.log(data?.a?.b?.c); // 12
console.log(data?.a?.b); // {c: 12, j: false}
console.log(data?.a?.b?.d ?? 'defaultValue'); // "defaultValue"
// console.log(data.a.b.d.e); // Uncaught TypeError: Cannot read properties of undefined (reading 'e')"
Enter fullscreen mode Exit fullscreen mode

When the path is generated at runtime. lodash supports this functionality with result and get. obj.a.b.c can only be specified at design time - i.e. when you write the code. Dealing with "self-describing data" it is sometimes necessary to formulate a path programmatically at runtime and then access (and/or mutate) it.

const text = '{"a":{"b":{"c":12,"j":false},"k":null}, "target":"a.b.c"}';
const data = JSON.parse(text);
const other = { a: { ...JSON.parse(text).a, d: { c: 0 } }, target: 'a.d.c' };

increment(data);   // i.e. increment at a.b.c
increment(other);  // i.e. increment at a.d.c

// ... just checking
console.log(data.a.b.c);   // 13
console.log(other.a.d.c);  //  1

function increment(data) {
  const path = data.target;
  const value = _.get(data, path);
  _.set(data, path, typeof value === 'number' ? value + 1 : 0);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
curiousdev profile image
CuriousDev

Yes, but I guess it is more like a challenge.