13

I want to make a function called createAssociativeArray which will recive two parameters: string and object, like this:

function createAssociativeArray(string, object) {
  //...
}

The last item of string should get the object data. See an use/return example:

createAssociativeArray('key1.key2.key3', {
  data1: 1,
  data2: 2,
  data3: 3
});

// key1: {
//   key2: {
//     key3: {
//       data1: 1,
//       data2: 2,
//       data3: 3
//     }
//   }
// }

What's the most simple and robust method to do it?

Use eval isn't is a possibility.


What I was tried:

function createAssociativeArray(string, object) {
  string = string.split('.');
  return string.reduce(function(_object, _target, i) {
    _object[_target] = (i + 1 === string.length ? object : {});
    return _object;
  }, {});
}

It didn't produced the expected result because the object is reseted to {}.

[JSFiddle]

2
  • 1
    Are you trying to implement namespaces? Also, where does the i variable come from? Commented Sep 25, 2015 at 22:25
  • @StefanBaiu, something like... It's a index from reduce (updated). Commented Sep 25, 2015 at 22:28

10 Answers 10

5

Here's what I came up with:

function createAssociativeArray(string, object) {
  var parts = string.split('.');
  var last = parts[parts.length - 1];
  var tree = {};

  var node = parts.slice(0, -1).reduce(function (memo, current) {
     return (memo[current] = {});
  }, tree);

  node[last] = object;
  return tree;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Try this if you want to merge with an exitsing Object (set the value on a JSON path in a given object): stackoverflow.com/a/32791758/2045312
3

I was curious to see if I could make a recursive solution, so here it is:

function createAssociativeArray(string, object) {
    if (string === "") return object;
    var stringarr = string.split('.');
    var laststr = stringarr.pop();
    var newobj = {};
    newobj[laststr] = object;
    return createAssociativeArray(stringarr.join("."), newobj);
}

Working JSFiddle demo: https://jsfiddle.net/pt352dxg/

Comments

2

Possible implementation:

Working demo

function createChain(keys, value) {
  var obj = {};
  var target = obj;
  keys = keys.split('.');
  keys.forEach(function(key, index) {
    target = target[key] = index === keys.length - 1 ? value : {};
  });
  target = value;
  return obj;
}

Comments

2

This function actually can accept an optional existing Object ({k:2, kk: 3, key1: 4}) and merge that with given json path. e.g. Try on chrome debugger console:

JSON.stringify(createAssociativeArray('key1.key2.key3', {  data1: 1,  data2: 2,  data3: 3}, {k:2,kk:3, key1:{}}))

will print this:

"{"k":2,"kk":3,"key1":{"key2":{"key3":{"data1":1,"data2":2,"data3":3}}}}"

..

  function createAssociativeArray(key, value, data) {
         if(!finalData && data)
           finalData = data;
         var finalData;
         if (!data)
             data = finalData = {};
         var keys = key.split('.');
         if (keys.length < 2) {
           data[keys[0]] = value; 
         } else {
           if (!data[keys[0]])
               data[keys[0]] = {};
           data = data[keys.shift()];              
           createAssociativeArray(keys.join("."),value,data);
         }
         return finalData;
    };

Comments

2

You were pretty close in your original attempt.

function createAssociativeArray(string, object) {
    return string.split('.').reverse().reduce(function (inner, key) {
        var outer = {};
        outer[key] = inner;
        return outer;
    }, object);
}

http://jsfiddle.net/xewoa06t/

Comments

1

This worked for me:

function createAssociativeArray(string, object){
    var array = string.split('.');
    var aArray = {};
    if(array.length > 1){
         aArray[array[array.length - 1]] = object;
         array.splice(array.length - 1, 1);
         createAssociativeArray(array.join('.'), aArray)
    }else{
        aArray[array[array.length - 1]] = object;
        return aArray
    } 
};


createAssociativeArray('key1.key2.key3', {data1: 1, data2: 2, data3: 3});

Basically, builds object from ground up, starting with the original object, then wrapping the 'layers' around it recursively

Comments

1

Nice case for a recursive function!

function createAssociativeArray(string, object) {
  if (string.split('.').length == 1) {
    var outObj = {};
    outObj[string] = object;
    return outObj;
  } else {
    var outObj = {};
    outObj[string.split('.')[0]] = createAssociativeArray(string.split('.').slice(1).join('.'), object);
    return outObj;
  }
}

Comments

0

It's easier with a simple loop, the key point is doing in reverse (like @JustcallmeDrago)

function createAssociativeArray(keys, data)
{
  var temp, keyPart
  
  for(keys = keys.split('.'); keys.length; data = temp)
  {
    keyPart = keys.pop()
    temp = {}
    temp[keyPart] = data
  }
  return data
}  

// TEST

x = createAssociativeArray("key1.key2.key3", { data1: "value1", data2: "value2" })

document.write('<pre>'+x+'\n'+x.key1 +'\n'
               +x.key1.key2 + '\n'
               +x.key1.key2.key3 +'\n'
               +x.key1.key2.key3.data1 +'\n'
               +x.key1.key2.key3.data2 +'</pre>')

Comments

0

Since no one have proviced a while-loop solution:

function namespace(path, context) {
    var obj = context;
    var s = path.split('.');
    var p;
    while (s.length) {
        p = s.shift();
        obj = obj[p] || (obj[p] = {});
    }
    return context;
}

Comments

0

ES6 one liner

(str, obj) => str.split('.').reverse().reduce((inner, key) => ({[key]: inner}), obj);

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.