Reputation: 13697
I have an object:
const list = {
library: {
books: {
count: 100
}
}
}
And I have an array:
const key = [ 'library', 'books', 'count' ]
I’d like to get the value 100
from the object using that array.
I’ve tried just using the array:
const list = {
library: {
books: {
count: 100
}
}
}
const key = [ 'library', 'books', 'count' ]
console.log(list[key])
No surprises here, returns undefined
.
And I’ve tried converting it to a string:
const list = {
library: {
books: {
count: 100
}
}
}
const key = [ 'library', 'books', 'count' ]
console.log(list[key.toString()])
Again obviously returns undefined
.
I can of course just loop through the object using the array – but I was hoping that somebody knew of a lovely one-liner that would work like magic.
Upvotes: 1
Views: 250
Reputation: 8730
What you are trying to implement is known as a namepath resolution.
You can achieve it, using reduce
, or a regular for
iteration.
I've prepared some benchmarks here : Performance test : reduce vs for loop
The for loop
, is aparently 10% faster than reduce
( tested in Chrome 65.0.3325 / Windows 10 0.0.0 )
Faster, and maybe easier to understand.
// namepath resolver
function resolvePath(target, namepath){
for( let i=0 ; i< namepath.length;i++ ) target = target[namepath[i] ];
return target;
};
// your target
const list = {
library: {
books: {
count: 100
}
}
};
// your namepath
const key = [ 'library', 'books', 'count' ];
alert( resolvePath(list, key) ) // outputs 100
Shorter and more elegant, but less intuitive at the beggining. And according to my performance tests, slower.
Usage: Mozilla Developer Documentation of Reduce
// your target
const list = {
library: {
books: {
count: 100
}
}
};
// your namepath
const key = [ 'library', 'books', 'count' ];
alert ( key.reduce((target,key) => target[key], list) )
If you don't care about security, and you are in the mood of entering the real danger zone...
eval( 'list.' + key.join('.') )
Definitely the shortest :D
(don't even think about using this)
Upvotes: 1
Reputation: 10148
Try this. A shorter version. Just for fun :)
const list = {
library: {
books: {
count: 100
}
}
}
const key = [ 'library', 'books', 'count' ]
console.log(list[key[0]][key[1]][key[2]])
Upvotes: 0
Reputation: 92461
The most succinct way I know is with reduce
:
const list = {
library: {
books: {
count: 100
}
}
}
const key = [ 'library', 'books', 'count' ]
// simple one-liner
let val = key.reduce((obj,key) => obj[key], list)
console.log(val)
Of course, you'll probably want to do some checks if you're dealing with inconsistent data.
You can also use a recursive function but not quite as short:
const list = {
library: {
books: {
count: 100
}
}
}
const key = [ 'library', 'books', 'count' ]
function getKey(obj, list) {
let key = list.shift()
if (key === undefined) return
let val = obj[key]
if (typeof val !== 'object') return val
return getKey(val, list)
}
let val = getKey(list, key)
console.log(val)
Upvotes: 3