Unflatten JS对象和转换数组

时间:2017-03-07 06:28:00

标签: javascript arrays json object ecmascript-6

我有一个用于压扁对象的函数:

let object = {
  a: 1,
  b: [
   { c: 2 },
   { c: 3 }
  ]
};

flatten(object)
// returns {
  'a': 1,
  'b.0.c': 2,
  'b.1.c': 3
}

我需要取消对象,但也要将数组恢复为原样。我有以下代码:

  unflatten(obj) {
    let final = {};

    for (let prop in obj) {
      this.assign(final, prop.split('.'), obj[prop]);
    }

    return final;
  }

  assign(final, path, value) {
     let lastKeyIndex = path.length-1;
     for (var i = 0; i < lastKeyIndex; ++ i) {
       let key = path[i];
       if (!(key in final)) {
         final[key] = {};
       }
       final = final[key];
     }
     final[path[lastKeyIndex]] = value;
  }

大部分都有效,但它会像这样处理数组:

{
  a: 1,
  b: { // Notice how b's value is now an object
   "0": { c: 2 }, // Notice how these now have a key corresponding to their index
   "1": { c: 3 }
  }
}

我需要b成为像以前一样的数组:

{
  a: 1,
  b: [
   { c: 2 },
   { c: 3 }
  ]
}

我不知道从哪里开始。它需要能够处理任意数量的数组,如:

'a.b.0.c.0.d',
'a.b.0.c.1.d',
'a.b.1.c.0.d',
'a.b.1.c.1.d',
'a.b.1.c.2.d',
// etc

它需要是vanilla JS,但是es2015很好。它假设任何一个数字的键实际上是数组的一部分。

如果有人有任何建议,我们表示赞赏!

2 个答案:

答案 0 :(得分:1)

当您发现key不在final中时,您应该检查路径中的下一个键是否只是数字(使用正则表达式),如果是,则分配给数组而不是对象:

if (!(key in final)) {
  final[key] = /^\d+$/.test(path[i + 1]) ? [] : {};
}

let object = {
  a: 1,
  b: [{
      c: 2
    },
    {
      c: 3
    }
  ]
};

let flattened = {
  'a': 1,
  'b.0.c': 2,
  'b.1.c': 3
}

function unflatten(obj) {
  let final = {};

  for (let prop in obj) {
    assign(final, prop.split('.'), obj[prop]);
  }

  return final;
}

function assign (final, path, value) {
  let lastKeyIndex = path.length - 1;
  for (var i = 0; i < lastKeyIndex; ++i) {
    let key = path[i];
    if (!(key in final)) {
      final[key] = /^\d+$/.test(path[i + 1]) ? [] : {};
    }
    final = final[key];
  }
  final[path[lastKeyIndex]] = value;
}

console.log(unflatten(flattened))
.as-console-wrapper { min-height: 100vh; }

答案 1 :(得分:0)

您可以迭代键,然后将字符串拆分为单个属性。要构建新对象,可以检查数字并为这些属性获取数组。

&#13;
&#13;
function setValue(object, path, value) {
    var way = path.split('.'),
        last = way.pop();

    way.reduce(function (o, k, i, kk) {
        return o[k] = o[k] || (isFinite(i + 1 in kk ? kk[i + 1] : last) ? [] : {});
    }, object)[last] = value;
}

function unFlatten(object) {
    var keys = Object.keys(object),
        result = isFinite(keys[0][0]) ? [] : {};
    keys.forEach(function (k) {
        setValue(result, k, object[k]);
    });
    return result;
}

console.log(unFlatten({
    'a': 1,
    'b.0.c': 2,
    'b.1.c': 3
}));
console.log(unFlatten({
    '0': 1,
    '1.0.c': 2,
    '1.1.c': 3
}));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;