Advanced-Frontend/Daily-Interview-Question

第 112 题:编程题,写个程序把 entry 转换成如下对象

yygmind opened this issue · 84 comments

var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

// 要求转换成如下对象
var output = {
  a: {
   b: {
     c: {
       dd: 'abcdd'
     }
   },
   d: {
     xx: 'adxx'
   },
   e: 'ae'
  }
}

我继续先来

 var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
  }

  function map(entry) {
    const obj = Object.create(null);
    for (const key in entry) {
      const keymap = key.split('.');
      set(obj, keymap, entry[key])
    }
    return obj;
  }

  function set(obj, map, val) {
    let tmp;
    if (!obj[map[0]]) obj[map[0]] = Object.create(null);
    tmp = obj[map[0]];
    for (let i = 1; i < map.length; i++) {
      if (!tmp[map[i]]) tmp[map[i]] = map.length - 1 === i ? val : Object.create(null);
      tmp = tmp[map[i]];
    }
  }
  console.log(map(entry));

题目

// 输入
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
};

// 要求转换成如下对象
var output = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
};

实现思路

遍历对象,如果键名称含有 . 将最后一个子键拿出来,构成对象,如 {'a.b.c.dd': 'abcdd'} 变为 {'a.b.c': { dd: 'abcdd' }} , 如果变换后的新父键名中仍还有点,递归进行以上操作即可。

// 输入
{
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}
// 1
t1 = {
    'a.b.c': { dd: 'abcdd' },
    'a.d': { xx: 'adxx' },
    a: { e: 'ae' }
};
// 2
// t1 = {
//     'a.b': { c: { { dd: 'abcdd' } },
//     a: { d: { { xx: 'adxx' } },
//     a: { e: 'ae' }
// };
// a.d 属性进行拆分时 需要新加入父键 a 而a已经存在 则进行合并
t2 = {
    'a.b': { c: { dd: 'abcdd' } },
    a: { e: 'ae', d: { xx: 'adxx' }  }
};
// 3
// t3 = {
//     'a': { b: { c: { dd: 'abcdd' } } },
//     a: { e: 'ae', d: { xx: 'adxx' }  }
// };
t3 = {
    a: { b: { c: { dd: 'abcdd' } }, e: 'ae', d: { xx: 'adxx' }  }
};

代码

function nested(obj) {
    Object.keys(obj).map(k => {
        getNested(k);
    });

    return obj;

    function getNested(key) {
        const idx = key.lastIndexOf('.');
        const value = obj[key];
        if (idx !== -1) {
            delete obj[key];
            const mainKey = key.substring(0, idx);
            const subKey = key.substr(idx + 1);
            if (obj[mainKey] === undefined) {
                obj[mainKey] = { [subKey]: value };
            } else {
                obj[mainKey][subKey] = value;
            }
            if (/\./.test(mainKey)) {
                getNested(mainKey);
            }
        }
    }
}

console.log(JSON.stringify(nested(entry), 0, 2));
const func2 = (input, output = {}) => {
  const generateKeys = (key, value, output = {}) => {
    const index = key.indexOf('.')
    if (index > 0) {
      const s = key.substring(0, index)
      const e = key.substring(index + 1)
      if (!output[s]) output[s] = {}

      generateKeys(e, value, output[s])
    } else {
      output[key] = value
    }
  }

  for (const k in input) {
    generateKeys(k, input[k], output)
  }
}

const o2 = {}
const input = func2(entry, o2)
console.log('o2', JSON.stringify(o2))
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
    'd.e.x': 'dex'
}
const obj = {};
Object.keys(entry).map((keyName) => {
    return keyName.split('.');
}).forEach(keysArr => {
    let currObj = obj;
    const keysArrLength = keysArr.length;
    for (let i = 0; i < keysArrLength; i += 1) {
        const keyItem = keysArr[i];
        if (!currObj[keyItem]) {
            currObj[keyItem] = i !== keysArrLength - 1 ? {} : entry[keysArr.join('.')];
        }
        currObj = currObj[keyItem];
    }
});
console.log(obj);
var deFlat = function(entry) {
  const res = {};
  for (let key in entry) {
    const sequenceKey = key.split('.');
    format(res, sequenceKey, entry[key]);
  }
  return res;
}

var format = function(obj, sequenceKey, value) {
  const key = sequenceKey.shift();
  if (!sequenceKey.length) {
    obj[key] = value;
  } else {
    obj[key] = obj[key] || {};
    format(obj[key], sequenceKey, value);
  }
}

var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

console.log(deFlat(entry))
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}
function setFlat (entry) {
    let res = {}
    function namespace(oNamespace, sPackage, value) {
        let iner = oNamespace
        let arr = sPackage.split('.')
        let len = arr.length
        arr.forEach((key, idx) => {
            iner = iner[key] = (idx === len - 1 ? value : (iner[key] instanceof Object ? iner[key] : {}))
        })
    }
    for (let k in entry) {
        namespace(res, k, entry[k])
    }
    return res
}
console.log(JSON.stringify(setFlat(entry)))
// {"a":{"b":{"c":{"dd":"abcdd"}},"d":{"xx":"adxx"},"e":"ae"}}
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function transObj(input) {
    let ouput = null
    let arr = Object.entries(input)
    arr.forEach((item,index)=>{
        let cellArr = item[0].split('.')
        let cellObj = {}
        let count = 0
        while(cellArr.length) {
            let key = cellArr.splice(-1)
            if(count == 0) {
                cellObj = {[key]:item[1]}
                count ++
            }else {
                if(ouput && ouput[key]) {
                    ouput[key] = Object.assign(ouput[key],cellObj)
                }else {
                    cellObj = {[key]:cellObj}
                }
                
            }  
        }
        if(!ouput) {
            ouput = cellObj
        }
    })
    return ouput
}

console.log(transObj(entry))
RGXMG commented

实现思路:

  1. 对象entry的key中含有的.就是一个对象嵌套,所以可以用split()函数将其划分为一个array,所以array的length - 1下标所对应的元素就是entry的一个key的具体值。
  2. 利用对象为地址引用原理,进行增加元素。
  3. 采用reduce函数,将每一次的引用返回。
const entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae',
};
const changObjStructureOfNormal = output => {
  const keys = Object.keys(output);
  const resObj = {};
  for (const key of keys) {
    const everyKey = key.split('.');
    everyKey.reduce((pre, next, index, array) => {
      if (index === array.length - 1) {
        pre[next] = output[key];
        return;
      }
      pre[next] = pre[next] || {};
      return pre[next];
    }, resObj);
  }
  return resObj;
};
changObjStructureOfNormal(entry);
function changeToNormal(obj) {
    let newObj = {};
    let t = newObj;
    const keys = Object.keys(obj);
    for (key of keys) {
        const fArr = key.split('.');
        while (fArr.length) {
            const val = fArr.length === 1 ? entry[key] : {};
            const tmpKey = fArr.shift();
            t[tmpKey] = t[tmpKey] || val;
            t = t[tmpKey];
        }
        t = newObj;
    }
    return newObj;
}
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function getOutput(obj) {
    let output = {};

    if (Object.prototype.toString.call(entry) === '[object Object]') {
        for (let i in obj) {
            let splitKey = i.split('.');

            (function getKeys(output, splitKey, value) {
                const key = splitKey.shift();
                if (!splitKey.length) {
                    output[key] = value;
                } else {
                    output[key] = output[key] || {};
                    getKeys(output[key], splitKey, value)
                }
            })(output, splitKey, obj[i])
        }
    } else {
        console.log('传入的不是对象');
    }

    return output;
}

getOutput(entry)

@RGXMG 我的实现思路和你这个一致,喜欢你这个👍

var entry = {
      'a.b.c.dd': 'abcdd',
      'a.d.xx': 'adxx',
      'a.e': 'ae'
    }
    const tranfer = (o, r = {}) => {
      for (let i in o) {
        var a = i.split('.')
        var j = 0
        var stack = [{
          parent: r,
          key: a[j]
        }]
        while (stack.length) {
          var item = stack.pop()
          j ++
          if (a[j]) {
            if (!item.parent[item.key]) {
              item.parent[item.key] = {}
            }
            stack.push({
              parent: item.parent[item.key],
              key: a[j]
            })
          } else {
            item.parent[item.key] = o[i]
          }
        }
      }
      return r
    }
 var entry = {
        'a.b.c.dd': 'abcdd',
        'a.d.xx': 'adxx',
        'a.e': 'ae'
      }

      function exchange(obj) {
        if (typeof obj != 'object') {
          throw new Error('请输入 [object Object] 类型')
        }
        // 对象转map
        let map = new Map()
        for (let key in obj) {
          let arr = key.split('.')
          map.set(arr, obj[key])
        }
        let O = {}
        let digui = function(map, object) {
          let obj = {}
          map.forEach((item, index, arr) => {
            // 取下标
            let key = index.shift(),
              length = index.length
            // 判断是否存在,不存在就添加
            if (!object[key]) {
              object[key] = length > 0 ? obj : item //判断是否为最后一个key,如果是就展示值,不是就继续递归
            }
            if (length > 0) {
              // 创建map结构
              let currMap = new Map()
              currMap.set(index, item)
              digui(currMap, object[key])
            }
          })
        }
        digui(map, O)
        return O
      }
      let res = exchange(entry)
      console.log(res)
var entry = {
  "a.b" : 111,
  "a.c" : 2222,
  "c.c" : 333,
  "c.a.c": 3333
}

let obj = {

}

for(let [path , v] of Object.entries(entry)) {
  let paths = path.split(".")
  let k;
  let cur = obj 
  // 最后一层路径
  let tail = paths.pop()
  // 迭代每层对象,在没有该路径情况下,创建,反之直接使用
  while(k = paths.shift()) {
    if(!cur[k]) {
      cur[k] = {
      
      }
    }
    // 切换到当前路径对象
    cur = cur[k]
  }
  // 将值赋值给最终位置
  cur[tail] = v 
}

console.log(obj);

基本思路

我的思路:

  • 遍历每一个需要展开的key,按照层级将其插入结果容器中。
  • 首次出现的key则创建,重复出现则跳过,统一进入下一个层级。
  • 当剩余展开深度为0则赋值

看到很多大神的回复,觉得有更好的思路可以实现,感觉自己这个比较普普通通哈哈。

/* 2019-07-24 */
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

var output = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}

// 要求将entry转化为output对象 (与昨日相反)



/* 解答 */

/**
 * 
 * @param {Object} target 展开的key所插入的目标对象
 * @param {Array} key 剩余需展开的key的数组
 * @param {String} value 最终的值
 */
const transform = (target = {}, key = [], value = 0) => {
  if (!key.length) return;  // 终止递归
  const currentKey = key.splice(0, 1);  // 截取当前首位key
  if (!target[currentKey]){
    target[currentKey] = key.length=== 0 ? value : {} ;  // 若当前属性为首次出现,则在对应深度创建该属性并赋值为空对象;若无剩余展开key时赋值
  }
  transform(target[currentKey], key, value);  // 进入下一次递归
}

const result = {};  // 结果容器
const keys = Object.keys(entry);  // 对象所需展开的字符串key
keys.map(item => transform(result, item.split('.'), entry[item]));
console.log(result);
var entry = {
 'a.b.c.dd': 'abcdd',
 'a.d.xx': 'adxx',
 'a.e': 'ae'
}
let obj = {};

for (let key of Object.keys(entry)) {
    key.split(".").reduce((s,c,i,a)=> {
        s[c] =  s[c] || (!a[i + 1] && entry[key]) || {};
        return s[c];
    }, obj);
}

console.log(JSON.stringify(obj));
var obj = {
 'a.b.c.dd': 'abcdd',
 'a.d.xx': 'adxx',
 'a.e': 'ae'
}
function entery(obj){

 let result = {}
 
 Object.getOwnPropertyNames(obj).forEach(key=>{
   getObj(key,obj[key],result)
     
 })
 
 
 function getObj(key,value,res){
   console.log(res);
      let keyArr = []
      let _length;
      keyArr = key.split('.');
      _length = keyArr.length;
      keyArr.forEach((item,index)=>{
        if(index ==_length-1){
          res[item] = value
        }else {
          res[item] = res[item] instanceof Object ? res[item]: {};
        }
        res = res[item];
      })

   
 }
  return result;
}
console.log(entery(obj));
const transform = entry => { 
  const result = {}; 
  for (let prop in entry) { 
    if (entry.hasOwnProperty(prop)) { 
      if (~prop.indexOf(".")) { 
        const arr = prop.split("."); 
        let curr = result;
         while (arr.length > 1) { 
           const item = arr.shift(); 
           if (!curr[item]) { 
            curr[item] = {}; 
          } 
          curr = curr[item]; 
        } 
        curr[arr.shift()] = entry[prop]; 
      } else { 
        result[prop] = entry[prop]; 
      } 
    } 
  }
  return result; 
};

实现

/** 将路径分解成数组 */
function pathToArray (path) {
  return Array.isArray(path) ? path : path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
}

/** 设置 object对象中对应 `path` 属性路径上的值 */
function set (object, path, value) {
  path = pathToArray(path)
  path.reduce((data, key, index) => {
    if (index !== path.length - 1) {
      if (!data[key]) { data[key] = {} }
    } else {
      data[key] = value
    }
    return data[key]
  }, object)
}

测试

const entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

const output = {}

for (const [key, value] of Object.entries(entry)) {
  set(output, key, value)
}

console.log(output)
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
};

function formatEntryToTree(obj) {
  var output = {};
  var handle = function(keys, value) {
    keys.reduce(function(before, now, index) {
      before[now] = index === keys.length - 1 ? value : output[now] || {};
      return before[now];
    }, output);
  };

  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      var keys = key.split('.');
      handle(keys, obj[key]);
    }
  }

  return output;
}

console.log(formatEntryToTree(entry));
var output = {}
var getObject = (data) => {
    for (let [k, v] of Object.entries(entry)) {
        let kList = k.split('.')
        let evalStr = 'output'
        kList.map((o, i) => {
            if (kList.length - 1 === i) {
                evalStr = evalStr + '.' + o
                eval(`${evalStr}='${v}'`)
            } else {
		if(!output.hasOwnProperty(o)){
			evalStr = evalStr + '.' + o
			eval(`${evalStr}={}`)
		}
            }
        })
    }
}
getObject(entry)
console.log(output)

eval()大法实现,

function convert (obj) {
	var returnObj = {};
	for (var key in obj) {
		var keyList = key.split('.');
		if (!returnObj[keyList[0]]) {
			returnObj[keyList[0]] = {};
		}
		var mapObj = returnObj[keyList[0]];
		for (var i = 1; i < keyList.length; i++) {
			var k = keyList[i];
			if (i === keyList.length - 1) {
				mapObj[k] = obj[key];
			} else {
				if (!mapObj[k]) {
					mapObj[k] = {};
				}
				mapObj = mapObj[k];
			}
		}
	}
	return returnObj;
}

对象是引用类型的想法

@RGXMG

const entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae',
};
const changObjStructureOfNormal = output => {
  const keys = Object.keys(output);
  const resObj = {};
  for (const key of keys) {
    const everyKey = key.split('.');
    everyKey.reduce((pre, next, index, array) => {
      if (index === array.length - 1) {
        pre[next] = output[key];
        return;
      }
      pre[next] = resObj[next] || {};
      return pre[next];
    }, resObj);
  }
  return resObj;
};
changObjStructureOfNormal(entry);

pre[next] = resObj[next] || {};错了,

const entry = {
    'a.b.c.dd': 'abcdd',
    'a.b.c.ee': 'abcee',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
  };
// output: {"a":{"b":{"c":{"ee":"abcee"}},"d":{"xx":"adxx"},"e":"ae"}}
// 'a.b.c.dd': 'abcdd' 被覆盖

pre[next] = resObj[next] || {};应该改为 pre[next] = pre[next] || {};

RGXMG commented

@pzjzeason

@RGXMG

const entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae',
};
const changObjStructureOfNormal = output => {
  const keys = Object.keys(output);
  const resObj = {};
  for (const key of keys) {
    const everyKey = key.split('.');
    everyKey.reduce((pre, next, index, array) => {
      if (index === array.length - 1) {
        pre[next] = output[key];
        return;
      }
      pre[next] = resObj[next] || {};
      return pre[next];
    }, resObj);
  }
  return resObj;
};
changObjStructureOfNormal(entry);

pre[next] = resObj[next] || {};错了,

const entry = {
    'a.b.c.dd': 'abcdd',
    'a.b.c.ee': 'abcee',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
  };
// output: {"a":{"b":{"c":{"ee":"abcee"}},"d":{"xx":"adxx"},"e":"ae"}}
// 'a.b.c.dd': 'abcdd' 被覆盖

pre[next] = resObj[next] || {};应该改为 pre[next] = pre[next] || {};

哈哈,好像是错了,估计是粘贴变量名的时候粘错了位置。感谢提醒

btea commented
function v(obj){
    let arr = Object.keys(obj);
    let $obj = {};
    arr.map(key => {
        let attrs = key.split('.');
        attrs.reduce((str, v) => {
            let s = `$obj.${str}`;
            if(!eval(s)){eval(`${s}={}`);}
            return str += '.' + v;
        });
        eval(`$obj.${key}=obj[key]`);
    });
    return $obj;
}
function transfer(entry) {
    const result = {}

    Object.entries(entry).forEach(([key, value]) => {
        const keyArr = key.split('.');

        result[keyArr[0]] = result[keyArr[0]] || {}
        let targetObj = result[keyArr[0]]

        for (let j = 1, length = keyArr.length; j < length; j++) {
            if (j < length - 1) {
                const tempObj = targetObj;
                
                targetObj = targetObj[keyArr[j]] || {}
                tempObj[keyArr[j]] = targetObj
            } else {
                targetObj[keyArr[j]] = value
            }
        }
    })

    return result;
}
function buildObj(obj) {
  let result = {}
  Object.keys(obj).forEach(key => {
    let stack = key.split('.'),
      res = result
    while(stack.length !== 0) {
      let k = stack.shift()
      if (!res.hasOwnProperty(k))
        res[k] = stack.length === 0 ? obj[key] : {}
      res = res[k]
    }
  })
  return result
}

//是不是也要考虑下值是别的类型的情况呀;比如是数组 number 之类的

var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
    'f.g':["a","b"]
}
console.log(transform(entry));
function transform(entry){
  const target = {};
  const map = new Map();
  Object.keys(entry).forEach(key=>{
    map.set(entry[key],key.split('.'));
  })
  map.forEach((vs,key)=>{
    _transform(target,key);
  })
  return target;
  function _transform(parent,key){
    const k = map.get(key).shift();
    if(!map.get(key).length){
      parent[k] = key;
    }else{
      if(!parent[k]){
        parent[k] = {};
      }
      _transform(parent[k],key);
    }
  }
}
const deepTree = obj => {
    let res = {}
    for (const [key, val] of Object.entries(obj)) {
      let arr = key.split('.')
      deep(res, arr, val)
    }

    function deep(obj, arr, val) {
      let key = arr.shift()
      if(key in obj){
        deep(obj[key], arr, val)
      }else if (arr.length > 0) {
        obj[key] = {}
        deep(obj[key], arr, val)
      }else{
        obj[key] = val
      }
    }
    return res
  }
let entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae',
  'b.d.e.s.e':'bdese',
  'a.v.d':'avd',
  'b.d.e.b':'bdeb'
}
let ret = {}; //保存最终结果的对象。
function convert(option) {
  for(var i in option) {
    let value = option[i];
    var keys = i.split(".")
    convertKeys(keys, ret, value);
  }
}

function convertKeys(keys, ret, value) {
  for(let i in keys) {
    let key = keys[i];
    let index = i;
     if(!ret[key]) {
        ret[key] = {};  
     } 
     if(keys.slice(index + 1).length > 0) {
          convertKeys(keys.slice(index +1), ret[key], value);
     } else { // 说明已经遍历到最后一个key, 不需要继续遍历了,直接赋值。
          ret[key] = value;
     }     
     break;
  }
}
convert(entry);
console.log(ret); //{"a":{"b":{"c":{"dd":"abcdd"}},"d":{"xx":"adxx"},"e":"ae","v":{"d":"avd"}},"b":{"d":{"e":{"s":{"e":"bdese"},"b":"bdeb"}}}}
function fnOutput(obj){
   let newObj = {}
   for(let key in obj){
       let nameArr = key.split('.')
       nameArr.reduce((pre,item,i)=>(pre[item]= i===nameArr.length-1 ? obj[key]  : (pre[item] || {})  ,pre[item]),newObj)
   }
   return newObj
}
const expendObj = (obj) => {
    var arr = [];
    var arr2 = [];
    for (key in obj) {
      arr.push(key.split("."))
      arr2.push(obj[key])
    }
    var res = {};
    arr.reduce((obj1, c, j) => {
      c.reduce((obj2, curr, i) => {
        obj2[curr] = obj2[curr] || {}
        if (i === c.length - 1) {
          obj2[curr] = arr2[j]
        }
        return obj2[curr]
      }, obj1)
      return res
    }, res)

    return res
  }
  console.log(expendObj(entry))
yft commented
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function fn (node) {
    let path, pathArr, i, len, obj, key;
    let res = {};
    for (path in node) {
        obj = res;
        pathArr = path.split('.');
        for (i = 0, len = pathArr.length - 1; i < len; i++) {
            key = pathArr[i];
            obj = obj[key] = obj[key] || {};
        }
        obj[pathArr[len]] = node[path];
    }
    return res;
}

console.log( JSON.stringify(fn(entry)) );
var entry = {
        'a.b.c.dd': 'abcdd',
        'a.d.xx': 'adxx',
        'a.e': 'ae',
        'text': 'text'
    }
    function go(obj,res) {
        for(key in obj){
            let arr = key.split('.');
            if(arr.length > 1){
                res[arr[0]] = res[arr[0]] || {};
                let cur = res[arr[0]];
                for(let i = 1;i<arr.length;i++){
                    if(i === arr.length -1){
                        cur[arr[i]] = obj[key]
                    }else{
                        if(!cur[arr[i]]){
                            cur[arr[i]] = {};
                        }
                        cur = cur[arr[i]];
                    }
                }
            }else{
                res[arr[0]] = obj[key]
            }
        }
        return res;
    }
    console.log(go(entry,{}))

我继续先来

 var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
  }

  function map(entry) {
    const obj = Object.create(null);
    for (const key in entry) {
      const keymap = key.split('.');
      set(obj, keymap, entry[key])
    }
    return obj;
  }

  function set(obj, map, val) {
    let tmp;
    if (!obj[map[0]]) obj[map[0]] = Object.create(null);
    tmp = obj[map[0]];
    for (let i = 1; i < map.length; i++) {
      if (!tmp[map[i]]) tmp[map[i]] = map.length - 1 === i ? val : Object.create(null);
      tmp = tmp[map[i]];
    }
  }
  console.log(map(entry));

当出现没有点的时候如下:
var entry = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae',
"f": "12345"
}
会出问题,因此在set里面要再做一层判断如下就更好了:
function set(obj, map, val) {
if(map.length === 1){
return obj[map[0]] = val
}
if(!obj[map[0]]) obj[map[0]] = Object.create(null)
let temp = obj[map[0]]
for(let i = 1;i< map.length;i++){
if(!temp[map[i]]) temp[map[i]] = i === map.length -1?val: Object.create(null)
temp = temp[map[i]]
}
}

const res = {};
const entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
};
for (let key in entry) {
    setKeypath(res, key, entry[key]);
}

function setKeypath(obj, keypath, value) {
    const keypaths = keypath.split(".")
    let key
    let lastKeyvalue = obj
    while (key = keypaths.shift()) {
        const keyvalue = lastKeyvalue[key] || {}
        lastKeyvalue[key] = keypaths.length ? keyvalue : value
        lastKeyvalue = keyvalue
    }
    return obj
}
function forMate(entry) {
  let res = {};
  Object.keys(entry).forEach(key => {
    key.split('.').reduce((pre, cur, index, arr) => {
      if (!pre[cur] && index !== arr.length - 1) {
        pre[cur] = {};
        return pre[cur];
      } else if (pre[cur] && index !== arr.length - 1) {
        return pre[cur];
      } else {
        pre[cur] = entry[key];
        return res;
      }
    }, res)
  });
  return res;
}

function switchObj(obj, result={}){
for(var key in obj){
~key.indexOf('.') ? key.split('.').reduce((r, item, index, arr) => {
if(index === arr.length - 1){
r[item] = obj[key]
return
}
r[item] = r[item] || {}
return r[item]
}, result ) : result[key] = result[key] || obj[key]
}
return result
}

看你们随随便便就写出来了,我光是理解就要好久。。。

            function getOO(obj) {
              var keys = Object.keys(obj)
              var res = {}
              var setfunc = (keyArr, res, val) => {
                // if (!res[keyArr[0]]) { res[keyArr[0]] = {} }
                if (keyArr.length > 1) {
                  let k = keyArr.shift()
                  res[k] = res[k] || {}
                  setfunc(keyArr, res[k], val)
                } else {
                  res[keyArr[0]] = val
                }
              }


              for (let key of keys) {
                let keyArr = key.split('.')
                //[a, b, c, dd] [a, d, xx] [a, e]
                setfunc(keyArr, res, obj[key])
              }
              console.log(res, 'resss')
              return res
            }

            getOO({
              'a.b.c.dd': 'abcdd',
              'a.d.xx': 'adxx',
              'a.e': 'ae'
            })
var exchangEntry = function (data) {
    var obj = {};
    for (var k in data) {
        var arr = k.split('.');
        var lastObj = obj;
        var j = void 0;
        while (j = arr.shift(), arr.length) {
            lastObj = lastObj[j] || (lastObj[j] = {});
        }
        lastObj[j] = data[k];
    }
    return obj;
};

递归函数即可

function reverseChange(obj) {
    const output = {}
    function giveProps(targetObj,props,index = 0) {
      if(index !== props.length - 1) {
        if(!targetObj[props[index]]) {
          targetObj[props[index]] = {}
          giveProps(targetObj[props[index]],props,++index)
        } else {
          giveProps(targetObj[props[index]],props,++index)
        }
      } else {
        console.log(targetObj[props[index]])
        console.log(props[index])
        targetObj[props[index]] = obj[props.join('.')]
      }
    }
    for(let k in obj) {
      const props = k.split('.')
      giveProps(output,props)
    }
    return output
  }
 var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
  }
console.log(reverseChange(entry)) 

和一楼大佬思路一样

var entry = {

    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
    'b.e':'cc',
}

doSth(entry)
function doSth(obj){
    let output = {}
    for (const key in obj) {
        console.log(key,obj[key]);
        let arr = key.split('.')
        if (!output[arr[0]]){
            output[arr[0]] = Object.create(null)
        }
        // output.a
        let moreObj = output[arr[0]]
        for (let i = 1; i < arr.length; i++) {
            //arr[i]:b,c,dd
            if (i == arr.length -1){
                moreObj[arr[i]] = obj[key]
            } else {
                moreObj[arr[i]] = Object.create(null)
            }
            // 取下一层a.b
            moreObj = moreObj[arr[i]]
        }
    }
    console.log(output);
}

不喜欢递归。

function expand (obj) {
    var keys = Object.keys(obj)

    var map = {}
    while (keys.length) {
        var current = keys.shift()

        var key = current.split('.')
        var tmp = {}
        for (var i = key.length - 1; i >= 0; i--) {        
            if (i === key.length - 1) {
                tmp[key[i]] = obj[current]
            } else {
                tmp[key[i]] = {
                    [key[i + 1]]: tmp[key[i + 1]]
                }
                delete tmp[key[i + 1]]
            }
            if (i === 0) {
                var k = Object.keys(map)
                if (key[0] === k[0]) {
                    map[key[0]] = Object.assign(map[key[0]], tmp[key[0]])
                } else {
                    map = Object.assign(map, tmp)
                    tmp = {}
                }
            }
        }
    }
    return map
}

分治版本
思路是遍历对象的每个属性,分别生成一个对象,然后将所有对象合并起来。

function spread(obj){
    //分别处理每个属性
    function toObj(key,value) {
        let obj = {};
        if(key.indexOf('.') !== -1){
            let temp = key.split('.');
            obj[temp[0]] = toObj(temp.slice(1).join('.'),value);
        }else {
            obj[key] = value
        }
        return obj;
    }
    //合并所有属性对象
    function assign(ori,tar){
        for(let key in ori){
            if(ori.hasOwnProperty(key) && tar.hasOwnProperty(key)){
                ori[key] = assign(ori[key],tar[key])
            }
        }
        return typeof ori === 'object' ? Object.assign(tar,ori) : ori;
    }
    let ans = {};
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            assign(toObj(key,obj[key]),ans)
        }
    }
    return ans;
}
function spread(input) {
  let entry = {};
  Object.keys(input).forEach(keys => {
    let prev = entry;
    let dots = keys.split('.');
    for (let i = 0; i < dots.length - 1; i++) {
      prev = prev[dots[i]] = prev[dots[i]] || {};
    }
    prev[dots[dots.length - 1]] = input[keys];
  });
  return entry;
}
function convert(data) {
      return Object.keys(data).reduce((res, keys) => {
        const value = data[keys];
        const keyList = keys.split(".");
        const lastKey = keyList.pop();
        const objResult = keyList.reduce((obj, key) => {
          if (!obj[key]) {
            obj[key] = {};
          }
          return obj[key];
        }, res);
        objResult[lastKey] = value;
        return res;
      }, {});
}
var  trans_obj = {
	"a.b.c.dd": "abcdd",
	"a.d.xx": "adxx",
	"a.e": "ae",
	"b": 1,
}
var entry1 = trans1(trans_obj);
console.log('entry1: ', entry1);
function trans1(obj) {
	var res = {};
	for (var [k, v] of Object.entries(obj)) {
		var arr = k.split('.');
		set(res, arr, v);
	}
	function set(obj1, keys, val) {
		if (keys.length > 1) {
			var key = keys.shift();
			if (!obj1[key]) {
				obj1[key] = {};
			}
			set(obj1[key], keys, val);
		} else {
			obj1[keys.shift()] = val;
		}
	}
	return res;
}
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

// 要求转换成如下对象
var output = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}

function transform (entry = {}) {
  const res = {}
  for (let key in entry) {
    if (entry.hasOwnProperty(key)) {
      next(key, entry[key], res)
    }
  }
  return res
}

function next (key, val, res) {
  let temp = res
  const arr = key.split('.')
  const len = arr.length
  for (let i = 0; i < len; i++) {
    const item = arr[i]
    if (!temp[item]) {
      temp[item] = i === len - 1 ? val : {}
    }
    temp = temp[item]
  }
}

console.log(transform(entry))

采用递归进行设置值,可能是比较清晰的一个方法了

function nested(obj){
    let result = {}
    Object.keys(aa).forEach(key=>{
        keyArrays = key.split('.')
        ObjectSet(result, keyArrays, obj[key])
    })

    function ObjectSet(o, keys, data){
        const key = keys.shift()
        if(keys.length===0){
            o[key] = data
        }else{
             if(typeof o[key] === 'undefined'){
            o[key] = {}
        }
             ObjectSet(o[key], keys, data)
        } 
    }
   return result
}
const getEntry = (entry)=>{
    var out = {};
    for(let e in entry){
        let arr = e.split(".");
        arr.reduce((t,v,n)=>{
            n != arr.length-1 ? (t[v] ? t[v] : t[v] = {}) : t[v]=entry[e];
            return t[v];
        },out);
    }
    return out;
};
Tnc-u commented
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
  }
function change(entry, res = {}){
    function setRes(obj, keyArr, val){
        let key = keyArr.shift()
        if(keyArr.length == 0){
            obj[key] = val
        }else{
            if(obj[key] === undefined){
                obj[key] = {}
                setRes(obj[key], keyArr, val)
            }else{
                setRes(obj[key], keyArr, val)
            }
            
        }
    }
    for(let key in entry){
        let val = entry[key]
        let keyArr = key.split('.')
        setRes(res, keyArr, val)
    }
    return res
}

console.log(change(entry))
const translate = obj => {
  const res = {}
  Object.keys(obj).forEach(key => {
    const keyArr = key.split('.')
    // let temp
    // keyArr.forEach((k, i) => {
    //   if (i == 0) { // 顶层属性
    //     res[k] = res[k] || {}
    //     temp = res[k]
    //   } else if (i === keyArr.length-1) { // 末层属性
    //     temp[k] = obj[key]
    //   } else { // 中间层的属性
    //     temp[k] = temp[k] || {}
    //     temp = temp[k]
    //   }
    // })
    keyArr.reduce((a, b, i) => {
      if (i === keyArr.length-1) {
        a[b] = obj[key]
      } else {
        a[b] = a[b] || {}
      }
      return a[b]
    }, res)
  })
  return res
}
function trans(obj) {
  let res = {}
  let temp
  for (let key in obj) {
    temp = res
    let arr = key.split('.')
    let len = arr.length
    for (let i = 0; i < len - 1; i++) {
      if (!temp[arr[i]]) {
        temp[arr[i]] = {}
      }
      temp = temp[arr[i]]
    }
    temp[arr[len - 1]] = obj[key]
  }
  return res
}
function parseToObj(obj) {
  return Object.keys(obj).reduce((res, path) => {
    const keys = path.split('.')
    const deepestObj = keys.slice(0, -1).reduce((o, key) => {
      o[key] = o[key] || {}
      return o[key]
    }, res)
    deepestObj[keys[keys.length - 1]] = obj[path]
    return res
  }, {})
}

const testObj = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}
console.log(parseToObj(testObj))
const entry2normal = (input: { [key: string]: string }) => {
  const result: { [key: string]: any } = {};
  const translator = (
    [key, ...resKeys]: string[],
    value: string,
    parent = result
  ) => {
    if (!resKeys.length) {
      parent[key[0]] = value;
      return;
    }
    if (!parent[key] || typeof parent[key] === 'string') parent[key] = {};
    translator(resKeys, value, parent[key]);
  };
  Object.entries(input).forEach(([key, value]) => {
    translator(key.split('.'), value);
  });
  return result;
};

有点像链表

var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

const search = (keys, res, value) => {
    let cur = res
    for (let i = 0; i < keys.length; i++) {
        if (i === keys.length - 1) {
            cur[keys[i]] = value
        } else if (!cur[keys[i]]) {
            cur[keys[i]] = {}
            cur = cur[keys[i]]
        }
    }
}

const solution = (obj) => {
    let res = {}
    for (let i in obj) {
        let keys = i.split('.')
        search(keys, res, obj[i])
    }
    return res
}

console.log(solution(entry))
function convert(entry) {
  let obj = {};
  for (const key in entry) {
    if (entry.hasOwnProperty(key)) {
      let keys = key.split(".");
// keys只有一个时直接赋值
      if (keys.length === 1) {
        obj[keys[0]] = entry[key];
        continue
      }
      if (!obj[keys[0]]) {
        obj[keys[0]] = Object.create(null);
      }
      // 储存对象最深属性的引用地址
      let temp;
      temp = obj[keys[0]];
      for (let i = 1; i < keys.length; i++) {
        if (i === keys.length - 1) {
          temp[keys[i]] = entry[key];
        } else {
          temp[keys[i]] = Object.create(null);
          temp = temp[keys[i]];
        }
      }
    }
  }
  return obj;
}
function translateEntery(entry) {
    const returnValue = {}
    if(typeof entry == 'object') {
        Object.keys(entry).forEach(key => {
            if(key.includes('.')) {
                const arr = key.split('.')
                generate(returnValue, arr, entry[key])
            }
        })
    }
    function generate(returnValue, arr, value) {
        if(arr.length == 1) {
            returnValue[arr.shift()] = value
            return 
        }
        const key = arr.shift();
        !returnValue[key] && (returnValue[key] = {});
        return generate(returnValue[key], arr, value)
    }
    return returnValue
}
const convert = function (obj) {
    const ans = {};

    function helper(o, prefix) {
        if (!o) {
            return;
        }

        Object.keys(o).forEach(k => {
            const v = o[k];
            const p = prefix ? `${prefix}.${k}` : k;

            switch (typeof v) {
                case 'string':
                case 'number':
                case 'boolean':
                case 'undefined':
                    ans[p] = v;
                    break;
                default:
                    helper(v, p);
                    break;
            }
        });
    }

    helper(obj, null);

    return ans;
};

var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
};

console.log(convert(entry));
// {
//     'a.b.c.dd': 'abcdd',
//     'a.d.xx': 'adxx',
//     'a.e': 'ae'
// };
function format(entry) {
    const result = {}

    Object.keys(entry).forEach((keyDot) => {
        const keys = keyDot.split(".");
        const value = entry[keyDot];

        let tmp=result;

        while (keys.length) {
            const key = keys.shift()

            if (keys.length === 0) {
                tmp[key] = value
            } else {
                tmp[key] = tmp[key] || {}
                tmp = tmp[key];
            }
        }
    })
    
    return result
}

// 要求转换成如下对象
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
};

console.log("debug-", format(entry));
function objTransitionStr(output) {
  const keySplit = Object.keys(output).map((key) => key.split("."));
  const values = Object.values(output);
  const res = {};
  keySplit.forEach((keys, i) => {
    keys.reduce((res, key, index) => {
      if (index === keys.length - 1) {
        res[key] = values[i];
      }
      return key in res ? res[key] : (res[key] = {});
    }, res);
  });
  return res;
}
XW666 commented
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
  }
  const find09 = (val) => {
    let obj = {}
    for (let key in val) {
      let keys = key.split('.')
      let bb = obj
      keys.forEach((item, index) => {
        if (!bb[item]) {
              bb[item] = index !== keys.length - 1 ? {} : val[key];
              bb = bb[item]
        }
      })
    }
  }
  find09(output)
var entry = {
        'a.b.c.dd': 'abcdd',
        'a.d.xx': 'adxx',
        'a.e': 'ae'
    }
    function gen(data){
        const obj = {} // 创建空对象
        Object.entries(data).forEach(([keys,val])=>{
            // 获取key 和 value
            let now = obj // 保存读取到的路径
            const path = keys.split('.') // 切割keys变成路径
            const key  = path.pop() // 弹出最后一个路径用来赋值
            path.forEach(key =>{ // 遍历路径创建
                if(!(key in now)){ // 如果路径不存在那么创建一个路径
                    now[key] = {}
                }
                now = now[key] // 进入路径
            })
            now[key] = val // 给最终路径赋值
        })
        return obj
    }

    console.log(gen(entry))

根据 x.y.z 来迭代

var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

function transformReverse(entry) {
  const output = {};
  Reflect.ownKeys(entry).forEach(key => {
    const val = entry[key];
    const keySplitByDot = key.split('.');
    let temp = output;
    while (keySplitByDot.length > 0) {
      const attr = keySplitByDot.shift();
      if (keySplitByDot.length === 0) {
        temp[attr] = val;
      } else {
        if (!temp[attr]) {
          temp[attr] = {};
        }
        temp = temp[attr];
      }
    }
  });
  console.log(output);
  return output;
}

transformReverse(entry)

1、使用一个额外的变量 preObj 来实现

function transform(obj) {
  var res = {}
  var preObj = res
  Reflect.ownKeys(obj).forEach((key) => {
    var keys = key.split('.')
    keys.forEach((v, i) => {
      if (i === keys.length - 1) {
        // 已达最后一个键值,赋值
        preObj[v] = obj[key]
        // 重置 preObj
        preObj = res
      } else {
        // 当前 key 已存在,则取值,否则创建新对象
        preObj[v] = preObj[v] || {}
        // 改变 preObj 指向,实现链式调用
        preObj = preObj[v]
      }
    })
  })
  return res
}

2、使用 reduce 简化

function transform(obj) {
  var res = {}
  Reflect.ownKeys(obj).forEach((key) => {
    var keys = key.split('.')
    keys.reduce((pre, cur, i) => {
      if(i === keys.length - 1) {
        pre[cur] = obj[key]
      } else {
        pre[cur] = pre[cur] || {}
        pre = pre[cur]
      }
      return pre
    }, res)
  })
  return res
}
// 测试
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae',
  k: 'k',
}

transform(entry)

image

kvsur commented
const entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
    'a.e.f': 'cover',
    'd.x': 'dx',
    'd': 'cover-d'
};

function format(entry) {
    const result = Object.create(null);

    for (let [key, val] of Object.entries(entry)) {
        const keys = key.split('.');
        set(keys.splice(0, 1)[0], keys.reduceRight((pre, k) => ({ [k]: pre }), val), result);
    }

    return result;
}

function set(key, val, obj) {
    // 基础类型的值的话就做覆盖操作
    (typeof obj[key] !== 'object' || typeof val !== 'object') && (obj[key] = val, true)
        || Object.entries(val).forEach(([k, v]) => set(k, v, obj[key]));
}

const result = format(entry);

console.log(JSON.stringify(result))

image

// 前缀树
const entryToTree = (entry: Dict<string>) => {
  const res = { root: {} } as Record<string, any>
  const pathes: string[][] = []

  for (const [k, v] of Object.entries(entry)) {
    pathes.push([...k.split('.'), v])
  }

  for (const path of pathes) {
    let root = res.root
    const key = path[path.length - 2]
    const value = path[path.length - 1]
    for (let i = 0; i < path.length - 2; i++) {
      const char = path[i]
      if (!Object.keys(root).includes(char)) root[char] = {}
      root = root[char]
    }
    root[key] = value
  }

  return res.root
}
XW666 commented
###  const find77 = (entry) => {
    let map = {}
    for (key in entry) {
      let m = key.split('.');
      let n = map;
      m.forEach((item, index) => {
        if (!n[item]) {
          n[item] = index !== m.length - 1 ? {} : entry[key]
          n = n[item]
        }
      })
    }
  }
function transform(obj) {
    let ret = {}
    function mergeObj(o1, o2) {
        Object.keys(o2).forEach(key => {
            if (key in o1) {
                o1[key] = mergeObj(o1[key], o2[key])
            } else {
                o1[key] = o2[key]
            }
        })
        return o1
    }
    Object.keys(obj).forEach(key => {
        let keyArr = key.split('.').reverse()
        let o = keyArr.reduce((pre, curKey) => {
            return {
                [curKey]: pre
            }
        }, obj[key])
        ret = mergeObj(ret, o)
    })
    console.log(ret.a.b.c)
}
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}
transform(entry)

参考: Rain120/Web-Study#18

var deFlatten = function (entry) {
    const res = {};

    var format = (res, keys, value) => {
        const key = keys.shift();

        if (!keys.length) {
            res[key] = value;
        } else {
            res[key] = res[key] || {};

            format(res[key], keys, value);
        }

    };

    for (const key in entry) {
        const keys = key.split('.');
        format(res, keys, entry[key]);
    }

    for (const key in res) {
        if (/^\w+\[\d+\]$/.test(key)) {
            const k = key.match(/^\w+/)[0];
            const i = key.match(/[\d+]/g).join('');

            res[k] = res[k] || [];
            res[k][i] = res[key];

            delete res[key];
        }
    }

    return res;
}

deFlatten({
    "a.b": 1,
    "a.c": 2,
    "asss.d.e": 5,
    "baa[0]": 1,
    "b[1]": 3,
    "b[2].a": 2,
    "b[20].b": 3,
    "c": 3
})

image

var entry2 = {
  "a.b.c.dd": "abcdd",
  "a.d.xx": "adxx",
  "a.e": "ae",
  "a.d.xy": "ae",
};

function foo(input) {
  const result = {};

  Object.entries(input).forEach(([k, v]) => {
    const keys = k.split(".");

    keys.reduce((acc, key, index) => {
      if (typeof acc[key] === "undefined") {
        acc[key] = Object.create(null);
      }

      if (index === keys.length - 1) {
        acc[key] = v;
      }

      return acc[key];
    }, result);
  });

  return result;
}

思路

  • 以"."将key分割成数组
  • 声明变量temp,利用js对象指向同一个引用地址的特性,把上一次的结果带进下一次循环中
  • length - 1为得到value的终止条件
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae',
}
/**
 * 转换
 * @author waldon
 * @date 2022-04-11
 * @param {*} entry - param
 */
function translateEntry(entry) {
  const res = {}
  for (const key of Object.keys(entry)) {
    const keyArr = key.split('.')
    const value = entry[key]
    let temp = res
    for (let i = 0, len = keyArr.length; i < len; i++) {
      const subKey = keyArr[i]
      if (i === keyArr.length - 1) {
        temp[subKey] = value
      } else {
        temp[subKey] = temp[subKey] || {}
        temp = temp[subKey]
      }
    }
  }
  return res
}

console.log(translateEntry(entry))

思路

  • 1 利用reduce写法, 将key转化为嵌套对象, 因为对象指向的是内存地址,会同步更新
  • 2 当到数组的最后一个值时,说明不再是对象,赋值即可
`
/**
 * 1 利用reduce写法, 将key转化为嵌套对象, 因为对象指向的是内存地址,会同步更新
 * 2 当到数组的最后一个值时,说明不再是对象,赋值即可
 * @param {*} obj 
 * @returns 
 */
function transform (obj) {
  const result = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (key.indexOf('.') > -1) {
        const arr = key.split('.');
        arr.reduce((pre, cur, index) => {
          pre[cur] = pre[cur] || {};
          if (index === arr.length - 1) { // 赋值
            pre[cur] = obj[key];
          }
          return pre[cur];
        }, result)
      } else {
        result[key] = obj[key];
      }
    }
  }

  return result
}
`
var entry = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function trans(obj) {
    const res = {}
    for (let key in obj) {
        let target = res
        const path = key.split('.')
        for (let i = 0, l = path.length - 1; i < l; i++) {
            target = (target[path[i]] = target[path[i]] || {})
        }
        target[path[path.length - 1]] = obj[key]
    }
    return res
}
function test(obj) {
  const res = {}
  for (const keys in obj) {
    const keyList = keys.split('.')
    const len = keyList.length
    const loop = (target, i) => {
      const key = keyList[i]
      if (i < len - 1) {
        loop(target[key] || (target[key] = {}), i + 1)
      } else {
        target[key] = obj[keys]
      }
    }
    loop(res, 0)
  }
  return res
}
xuhen commented
function convert(obj) {
    const result = {};
    for (let k of Object.keys(obj)) {
        const paths = k.split('.');
        paths.reduce((ac, cur, idx) => {
            if (!ac[cur]) {
                if (idx === arr.length - 1) {
                    ac[cur] = obj[k];
                } else {
                    ac[cur] = {};
                }
            }
            return ac[cur];
        }, result)

    }
    return result;
}
const entry = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
};

function cook(obj) {
  let res = {};
  Object.keys(obj).forEach(keyPath => {
    const value = obj[keyPath];
    const list = keyPath.split('.');
    list.reduce((acc, key, index) => {
      if (index === list.length - 1) {
        acc[key] = value;
        return;
      } else {
        acc[key] = acc[key] || {};
        return acc[key];
      }
    }, res);
  });
  return res;
}
function test(obj) {
        const result = {};
        for (const key of Object.keys(obj)) {
          const list = key.split(".");
          let temp = result;
          while (list.length) {
            let keyvalue = list.shift();
            temp[keyvalue] = list.length ? temp[keyvalue] || {} : obj[key];
            temp = temp[keyvalue];
          }
        }
        return result;
      }
var data = {
  'a.b.c': 'ccc',
  'a.b.d': 'ddd',
  'a.e': 'eee'
}

function solution(data) {
  var result = {}

  Object.keys(data).forEach((key) => {
    const arr = key.split('.');
    arr.reduce((acc, cur, index) => {
      acc[cur] = acc[cur] || {}
      if (index === arr.length - 1) {
        acc[cur] = data[key]
      }

      return acc[cur]
    }, result)
  })

  return result
}

console.log('solution: ', solution(data));
function transfer(entry) {
  const result = {};

  Object.entries(entry).forEach(([string, value]) => {
    const keys = string.split('.');
    let temp = result;

    keys.forEach((key, index) => {
      if (index === keys.length - 1) {
        temp[key] = value;
      } else if (typeof temp[key] === 'undefined') {
        temp[key] = {};
      }

      temp = temp[key];
    });
  });

  return result;
}
var entry = {
  'a.b.c.dd': 'abcdd',
  'a.b.c.d.e': 'abcde',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}
function convert4(entry) {
  const result = {};
  for (let key of Object.keys(entry)) {
    key.split('.').reduce((acc, cur, i, paths) => acc[cur] ??= (i === paths.length -1 ? entry[key] : {}), result)
  }
  return result;
}
console.log(convert4(entry))
function format(obj) {
  const result = {};

  for (let key in obj) {
    const arr = key.split(".");

    dfs(arr, result, obj[key]);
  }

  return result;

  function dfs(array, target, value) {
    if (!array.length) {
      return;
    }

    const key = array[0];

    if (array.length === 1) {
      target[key] = value;
    } else {
      const copiedArray = [...array];

      target[key] = target[key] || {};
      copiedArray.shift();
      dfs(copiedArray, target[key], value);
    }
  }
}

// output = {
//   a: {
//     b: {
//       c: {
//         dd: 'abcdd'
//       }
//     },
//     d: {
//       xx: 'adxx'
//     },
//     e: 'ae'
//    }
//  }
console.debug(
  format({
    "a.b.c.dd": "abcdd",
    "a.d.xx": "adxx",
    "a.e": "ae",
  })
);