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

  • 2
    Please note that you're not using the arrays as such, you're adding properties to the objects, javascript has no associative arrays. – LJᛃ Dec 18 '14 at 15:19
  • 1
    It is not clear what you are actually trying to do here. – Mike Brant Dec 18 '14 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. – Thomas Dorloff Dec 20 '14 at 21:15

4 Answers4

2

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 :)

FTav
  • 389
  • 4
  • 13
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 `[]`
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
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.

Erik Gillespie
  • 3,929
  • 2
  • 31
  • 48
  • 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. – Thomas Dorloff Dec 20 '14 at 21:05
  • 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. – Erik Gillespie Dec 21 '14 at 18:32
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
Gnucki
  • 5,043
  • 2
  • 29
  • 44