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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.