通过字符串键/路径生成一个嵌套对象结构

13

我想要创建一个名为createAssociativeArray的函数,它将接受两个参数:stringobject,格式如下:

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

string 的最后一个项目应该获取 object 数据。参见使用/返回示例:

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

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

最简单和最稳健的方法是什么?

使用 eval 不是一个可行的选择。


我尝试过的方法:

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

由于对象被重置为{},它未产生预期结果。

[JSFiddle]


1
你是否正在尝试实现命名空间?另外,变量i是从哪里来的? - user2844991
@StefanBaiu,类似这样...它是来自reduceindex(已更新)。 - Caio Tarifa
10个回答

5

这是我的结论:

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;
}

如果您想要与现有对象合并(在给定对象中设置JSON路径上的值),请尝试以下内容:https://dev59.com/4VwY5IYBdhLWcg3wTGFu#32791758 - TechMaze

3

我很好奇能否制作一种递归解决方案,所以这里是:

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);
}

操作JSFiddle演示:https://jsfiddle.net/pt352dxg/


2
可能的实现方式: 演示链接
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;
}

2

这个函数实际上可以接受一个可选的现有对象({k:2,kk:3,key1:4}),并将其与给定的JSON路径合并。例如,在Chrome调试器控制台中尝试:

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

将会打印出这个:

"{"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;
    };

2
你的原始尝试非常接近。
function createAssociativeArray(string, object) {
    return string.split('.').reverse().reduce(function (inner, key) {
        var outer = {};
        outer[key] = inner;
        return outer;
    }, object);
}

http://jsfiddle.net/xewoa06t/


1
这对我有用:

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});

基本上,从原始对象开始,逐层递归地包装“层”,构建出一个新的对象。

1
不错的递归函数案例!
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;
  }
}

0

用一个简单的循环会更容易,关键是要倒序操作(像 @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>')


0

ES6一行代码

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

0

由于没有人提供一个while循环的解决方案:

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接