0

With an array, a value, and and an object with nested objects:

Object

mesh

Array

['options', 'range', 'x']

Value

12.5

Is it possible to translate this to update a property, e.g.

mesh.options.range.x = 12.5

Attempted:

index = (obj, i) ->
   obj[i]

arr.reduce(index, obj) = 12.5

Update

Thank you all for the elegant solutions.

5
  • What do you mean by "translate"? Commented May 29, 2014 at 20:56
  • 1
    Ohh - we wants to loop the array and add properties to the object. Ok. WHAT HAVE YOU TRIED? Commented May 29, 2014 at 20:56
  • Are you asking if there is a way to convert the contents of an array to an object and then set it to the value? Commented May 29, 2014 at 20:57
  • Convert it to an assignment Commented May 29, 2014 at 20:57
  • you can make a simple resolve() utility using [].reduce() Commented May 29, 2014 at 20:59

4 Answers 4

2

Using .reduce() is actually pretty nice for this:

// current object----|    |----current key
//                   v    v
arr.reduce(function(obj, key) {
    return obj == null ? obj : obj[key];
}, window.mesh);
//        ^
//        |-- initial object

Your attempt to use .reduce() needed to pass a function that manages the "accumulation".

Here, as long as the previous obj wasn't null or undefined, it'll return the key of the current obj, which becomes the next obj.


Then since you need to assign a value, you'd actually want to get the value of the second to last key.

var o = arr.slice(0,-1).reduce(function(obj, key) {
    return obj == null ? obj : obj[key];
}, window.mesh);

And then check its existence and use the last item in arr to do the assignment.

o && o[arr.pop()] = 12.5;

All of this can be abstracted away into a function that does one or the other based on how many arguments were passed.

function setFromArray(obj, arr, val) {
    var keys = arguments.length < 3 ? arr.slice() : arr.slice(0, -1);

    var o = keys.slice(0,-1).reduce(function(obj, key) {
        return obj == null ? obj : obj[key];
    }, window.mesh);

    if (arguments.length < 3)
        return o;
    else 
        o && o[keys.pop()];
}
Sign up to request clarification or add additional context in comments.

5 Comments

Nice. I'm having a hard time wrapping my head around which solution is better vs. Jake's -- performing the assignment inside vs. externally
@TaylorMac: I think it doesn't really make much difference. Mostly just a personal preference. His solution is good too. As long as the approach is abstracted away into a function, it'll be clean.
...one change he may want to make would be to make sure that each item in the path produces an object for the next iteration. Otherwise the program could fail with a TypeError.
Just tested. Thank you mr. cookie monster
@TaylorMac: You're welcome. And I just noticed that in my last two examples, I forgot to type [key], so that's fixed now. You probably figured that out.
2

Here's a general solution:

function setPropertyPath(obj, path, value) {
    var o = obj;
    for (var i = 0; i < path.length - 1; i++) {
        o = o[path[i]];
    }
    o[path[path.length - 1]] = value;
}

Usage:

var obj = { a: { b: { c: 0 } } };
setPropertyPath(obj, ['a', 'b', 'c'], 10);
console.log(obj.a.b.c); // prints '10'

JSBin

1 Comment

Thank you for handling the assignment
0
var mesh = {},
    arr = ['options','range','x'],
    value = 12.5;

mesh[arr[0]][arr[1]][arr[2]] = value;

Comments

0

If array length is static do something like this:

mesh[array[0]][array[1]][array[2]] = value;

However, one problem with this is that javascript doesn't do autovivification, so if you're accessing a key value that isn't previously defined you could run into errors (if mesh.options hasn't been defined then the above will throw an error because you can't assign to it). To solve that you might abstract this out into a function that handles things recursively:

http://jsfiddle.net/h4jVg/

function update_val(obj, array, val, prev) {
    if (array.length == 0) {
        obj = val;
        return;
    }

    var cur = array.shift();

    if(array.length == 0) {
        obj[cur] = val;
        return;
    } else if (obj[cur] == undefined) {
        obj[cur] = {};
    }

    update_val(obj[cur], array, val);
}

1 Comment

Also a great recursive solution. Wondering how this performs compares to Jake King & cookie monster

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.