【问题标题】:Unflatten JS object and convert arrays展开 JS 对象并转换数组
【发布时间】:2017-07-27 06:25:16
【问题描述】:

我有一个函数可以像这样展平对象:

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

需要是原生 JS,但 es2015 没问题。它假设任何一个数字键实际上都是数组的一部分。

如果有人有任何建议,不胜感激!

【问题讨论】:

    标签: javascript arrays json object ecmascript-6


    【解决方案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; }

    【讨论】:

      【解决方案2】:

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

      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
      }));
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-04
        • 2017-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多