3

Maybe there is already a solution, but I can't find it. I try to access different slots in a multi dimensional array dynamical but with the challenge of different depths. Basically, it looks like this:

var source = [];
source['lvl1'] = [];
source['lvl1']['lvl2a'] = [];
source['lvl1']['lvl2a']['lvl3'] = "ping";
source['lvl1']['lvl2b'] = "pong";

If the depth is fix, I could write code like this:

var path1 = ["lvl1","lvl2a","lvl3"];
var path2 = ["lvl1","lvl2b"];

console.log(source[path1[0]][path1[1]][path[2]]); // => ping
console.log(source[path2[0]][path2[1]]); // => pong

My problem is to write a code that works for both variants. This would work:

switch(path.length)
{
  case 1:
    console.log(source[path[0]]);
    break;
  case 2: 
    console.log(source[path[0]][path[1]]);
    break;
  case 3:
    console.log(source[path[0]][path[1]][path[2]]);
    break;
}

But this is neither efficient nor elegant. Has somebody another solution that works for example with some kind of loop?!?

Thanks Thomas

3
  • 2
    Please note that you're not using the arrays as such, you're adding properties to the objects, javascript has no associative arrays. Commented Dec 18, 2014 at 15:19
  • 1
    It is not clear what you are actually trying to do here. Commented Dec 18, 2014 at 15:23
  • Finally, I try to develop a generic editor for json configuration files. I have some kind of schema file taht describes the json then my script on the one hand creates a html form to edit the data and on the other hand writes back the changes into the json structure. Reading ist not difficult but updating a value within the structure is. Commented Dec 20, 2014 at 21:15

4 Answers 4

3

This question has been answered quite some time ago, but I'd like to show a really simple one line solution using the array reducer:

const getRoute = (o, r) => r.split(".").reduce((c, s) => c[s], o);

let q = {a:{b:{c:{d:"hello world"}}}};

console.log(getRoute(q, 'a.b.c.d'));

This might help someone else :)

Sign up to request clarification or add additional context in comments.

1 Comment

Holy smokes. Not what I came here for, but thank you so much!
1

If you are sure that all the values in the array will exist, then you can simply use Array.prototype.reduce, like this

console.log(path1.reduce(function(result, currentKey) {
    return result[currentKey];
}, source));
# ping

You can make it generic, like this

function getValueFromObject(object, path) {
    return path.reduce(function(result, currentKey) {
        return result[currentKey];
    }, object);
}

And then invoke it like this

console.assert(getValueFromObject(source, path1) === "ping");
console.assert(getValueFromObject(source, path2) === "pong");

Note: You need to make sure that the source is a JavaScript object. What you have now is called an array.

var source = {};   # Note `{}`, not `[]`

5 Comments

OP needs an Object. Not an array, since he is using keys.
@AmitJoki I am not getting you, what is not an Array? Can you please explain?
I deleted my previous comment, refresh the page.
@AmitJoki Nope, that comment is for the first comment only.
When OP is doing var source = []; source["key"], it is apt to use Array. Also my first comment was commented before you edited to make source an object.
0

You can loop and build up the value of source before logging it. Try this out:

var sourceValue = source[path[0]];
for (var i = 1; i < path.length; i++) {
    sourceValue = sourceValue[path[i]];
}
console.log(sourceValue);

Here's a JSFiddle that demonstrates this approach works.

2 Comments

Hmm, I have to test it. Actually, my primary intention is not only to read a value (which would work with this approach) but to set a new value. When I am right, you extract the value by reducing the original object to the parts described by the path array but you also destroy the original object.
If you loop until path.length-1 then you will have a reference to the container of the value you want and can make modifications to that.
0

You can get a value from a path (tested code):

var getValue = function(path, context) {
    if ('object' !== typeof context) {
        throw new Error('The context must be an object; "' + typeof context + '" given instead.');
    }
    if ('string' !== typeof path) {
        throw new Error('The path must be a string; "' + typeof context + '" given instead.');
    }

    var fields = path.split('.'),
        getValueFromFields = function(fields, context) {
            var field = fields.shift();

            if (0 === fields.length) {
                return context[field];
            }

            if ('object' !== typeof context[field]) {
                throw new Error('The path "' + path + '" has no value.');
            }

            return getValueFromFields(fields, context[field]);
        }
    ;

    return getValueFromFields(fields, context);
}

var source = [];
source['lvl1'] = [];
source['lvl1']['lvl2a'] = [];
source['lvl1']['lvl2a']['lvl3'] = "ping";
source['lvl1']['lvl2b'] = "pong";

console.log(getValue('lvl1.lvl2a.lvl3', source)); // ping
console.log(getValue('lvl1.lvl2b', source));      // pong

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.