// Problem:
/*
- 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
*/
var obj = {
a: {
b: {
c: 12,
j: false
},
k: null
}
};
// Solution:
const findPath = (object, path) => {
let i=1;
const pathList = path.split('.');
let obj = object[pathList[0]];
while(i<pathList.length) {
if(typeof obj === 'object') {
obj = obj[pathList[i]];
i++;
} else {
return undefined;
}
}
return obj;
};
// cases
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
console.log(findPath(obj, 'a.c')); // undefined
console.log(findPath(obj, 'a.b.c.d')); // undefined
console.log(findPath(obj, 'a.b.c.d.e')); // undefined
console.log(findPath(obj, 'a.b.j')); //false
console.log(findPath(obj, 'a.b.j.k')); //undefined
console.log(findPath(obj, 'a.k')); //null
thanks
Top comments (26)
The problem with this is that if you do something like:
And then you try to get it:
You get
undefined
, because you're using "." to split the path.This could be an impossible case as no one could assign key as dot. Anyhow, my solution is to cover the use cases mentioned.
You can also directly define "
.
" in the object declaration as well.Yup, my first example had that 😅
I think you forgot you can format objects like JSON (JavaScript Object Notation):
I was referring to real world scenario. No one uses any object key as dot alone.
Usually, programmers give readable key name based on their requirement.
Everything has its corner cases, I am generalizing concept to find the path. It is not that I need to cover all worst cases.
Hope you guys get it. Also, it would be better if you guys provide solution for the case you are mentioning. That might worth for the people came across this article.
Thank you.
The simplest solution would be to do away with
split
and instead consider a token-based approach:"."
refers to a field called"."
on the root, whereas"foo.."
refers to a field called"."
on the nested object at root-key"foo"
. And then"foo...bar"
refers to afoo->.->bar
path.However, this also causes some ambiguity:
foo.....bar
could be eitherfoo->.->.->bar
orfoo->...->bar
.A generalized solution would then use escape sequences. e.g.
\.
for a dot literal,\\
for a backslash literal, but that naturally makes parsing the path ever so more complex.I like ðis approach.
Sure it requires some more complexity and probably takes longer (but not too much) than
.split(char_seq)
but it gets ðe job done and better.Ðis could be solved by checking ðe more specific case (
foo->.->.->ba
) first and if ðat fails try ðe simpler one(s).Of course it won't be perfect but it can at least try to figure out intentions.
If you use an object to represent directories and files with their respective data, you could use
"."
to represent the current directory. Something like:The idea is that you should support all valid keys, and that includes keys with dots. All the above will fail because they have dots on them. I would just not have a function like this, and instead use optional chaining, to be honest:
A
Symbol
is a valid key 😂IKR ... the only way I can think to implement that with a function like this would be using template literals and doing something like
path.to.${Symbol("example")}
.... and is way more complex than just using optional chaining (path?.to?.[Symbol("example")]
) 😅Symbols in template strings =
TypeError: can't convert symbol to string
:)I was talking about doing something like this:
That logs:
Ðat's why ðey have a
.toString()
meþod, I believe.Recursion makes for a simpler solution:
As Frank Wisniewski suggests, try Optional Chaning.
It works on more than just object properties as well. It also lets you optionally call functions.
Yes. Optional chaining is latest feature and might not be used (or enabled) everywhere. If someone is using then cool otherwise we need to follow traditional way.
Unless you're planning on supporting unsupported browsers such as Internet Explorer, then optional chaining is supported pretty much everywhere ... and even if it isn't, you can use Babel or TypeScript to compile your modern code to support unsupported browsers.
This confused me initially because of the function name - I thought we were going to find a path to a property with a given value, but we're actually doing the opposite. A better name might be
getPropertyWithPath
findPath
similar togetPropertyPath
. I hope people would get it as I am referring to object.Does that really make sense?
gives the same result
True, but I þink ðis is more for backwards compatibility.
But yes, newer code should probably use Optional Chaining.
Yes. Optional Chaining is the best and more readable.
But this isn't really doing the same thing? It's not dynamic
I don't understand what you mean by that..