【问题标题】:Flatten nested JavaScript object展平嵌套的 JavaScript 对象
【发布时间】:2020-06-23 12:09:59
【问题描述】:

我有一个嵌套对象,我想将它展平/映射成一个单层、类似表格的对象。

[{
    a: 1,
    b: 2,
    c: [{
        x: 10,
        y: 20
    }, {
        x: 30,
        y: 40
    }]
}, {
    a: 3,
    b: 4,
    c: [{
        x: 50,
        y: 60
    }, {
        x: 70,
        y: 80
    }]
}]

由此,我想得到这样的东西:

[{
    a: 1,
    b: 2,
    x: 10,
    y: 20
}, {
    a: 1,
    b: 2,
    x: 30,
    y: 40
}, {
    a: 3,
    b: 4,
    x: 50,
    y: 60
}, {
    a: 3,
    b: 4,
    x: 70,
    y: 80
}]

当然,我可以简单地用两个 for 循环遍历对象并将结果信息放在一个单独的数组中,但我想知道是否有更简单的解决方案。我已经尝试过使用flatMap。如果我只想要嵌套对象的c 部分,它就可以工作,但我不知道如何将ab 映射到这个对象。

正如你们中的一些人要求提供一些工作代码,应该这样做(未经测试):

let result = [];

for (const outer of myObj)
  for (const inner of outer.c)
    result.push({a: outer.a, b: outer.b, x: inner.x, y: inner.y});

问题是,如果有一种功能性的单线甚至另一种更好的方法。实际上,我的对象由四层组成,嵌套的 for 循环很快就会变得混乱。

【问题讨论】:

  • 如果您实际上没有任何问题,这可能更适合codereview.stackexchange.com
  • 你在这里并不讨人喜欢,因为如果是的话,你会有重复的 x 和 y。也是这个结构总是这样,如果{x,y}有另一个子数组,这个会更多吗?
  • @Brewal 绝对不是 codereview 的问题。
  • @Brewal 但是他们在 codereview 修复现有的和工作的代码,当根本没有代码比这里更难回答时。
  • @Teemu 我认为实际上已经有一个可行的解决方案。

标签: javascript flatmap


【解决方案1】:

使用两个减速器来扁平化你的结构

const input = [{
  a: 1,
  b: 2,
  c: [{
    x: 10,
    y: 20
  }, {
    x: 30,
    y: 40
  }]
}, {
  a: 3,
  b: 4,
  c: [{
    x: 50,
    y: 60
  }, {
    x: 70,
    y: 80
  }]
}]

const result = input.reduce((acc_0, x) => {
  return [...acc_0, ...x.c.reduce((acc_1, y) => {
    const obj = {
      a: x.a,
      b: x.b,
      x: y.x,
      y: y.y
    }
    acc_1.push(obj);
    return acc_1;
  }, [])]
}, []);

console.log(result)

【讨论】:

    【解决方案2】:

    flatMap 解决方案如下所示:

    const result = myObj.flatMap(outer =>
      outer.c.map(inner =>
        ({a: outer.a, b: outer.b, x: inner.x, y: inner.y})
      )
    );
    

    当然,如果您的对象有多个层,而不仅仅是两个,甚至可能有多个或未知的具有这种嵌套的属性,您应该尝试实现递归解决方案。或者是一个迭代的,循环遍历一组属性名称(例如,["c"])并逐级应用展平。

    【讨论】:

    【解决方案3】:

    您可以在属性“c”上使用flatMap 方法和map

    var input = [{ a: 1, b: 2, c: [{ x: 10, y: 20 }, { x: 30, y: 40 }] }, { a: 3, b: 4, c: [{ x: 50, y: 60 }, { x: 70, y: 80 }] }];
    
    const output = input.flatMap(obj =>
      obj.c.map(arr => ({a: obj.a, b: obj.b, x: arr.x, y: arr.y}))
    );
    
    console.log(output);

    【讨论】:

    【解决方案4】:

    理想情况下,解决方案将需要一些东西来说明开始将对象分类为完整对象的程度,一个简单的解决方案就是通过您想要的级别。如果你不想通过关卡,你可以做一个检查,如果没有一个属性有数组,那么你会把它归类为一个完整的记录,但当然这个逻辑是你需要确认的。

    如果您想要一个适用于多个级别的通用版本,如果您通过了级别并使用递归,您可以执行以下操作 ->

    const a=[{a:1,b:2,c:[{x:10,y:20},{x:30,y:40}]},{a:3,b:4,c:[{x:50,y:60},{x:70,y:80}]}];
    
    
    function flattern(a, lvl) {
      const r = [];
      function flat(a, l, o) {
        for (const aa of a) {
          o = {...o};
          for (const [k, v] of Object.entries(aa)) {
            if (Array.isArray(v) && l < lvl) flat(v, l + 1, o);
            else o[k] = v;
          }
          if (l === lvl) r.push(o);
        }
      }
      flat(a, 1);
      return r;
    }
    
    console.log(flattern(a, 2));
    //console.log(flattern(a, 1));

    【讨论】:

    • 感谢您提供解决方案。我创建了一个 jsperf:jsperf.com/unfold-complex-object/1
    • @AndréReichelt 并不是一个公平的 jsperf 比较,因为我的解决方案是唯一的通用解决方案 :),说对于通用解决方案来说,慢 14% 似乎也不错,所以这很有趣..
    • 我实际上决定将您的想法标记为解决方案,因为它唯一的通用方法。如果我将来更改 C# 类的任何内容,它是维护量最少的一个。
    • 是否很难修改您的代码,使其也扁平化非数组属性?我的结构包含两个属性,它们只是单个对象。
    • @AndréReichelt 我相信修改应该不会太难。考虑到这一点,您可以敲出示例输入/输出。也可能是一个想法,可以提出另一个问题并在需要时参考这个问题。
    【解决方案5】:

    使用reduce的解决方案之一是:

    const list = [{
        a: 1,
        b: 2,
        c: [{
            x: 10,
            y: 20
        }, {
            x: 30,
            y: 40
        }]
    }, {
        a: 3,
        b: 4,
        c: [{
            x: 50,
            y: 60
        }, {
            x: 70,
            y: 80
        }]
    }]
    
    const flatten = (arr) => {
      return arr.reduce((flattened, item) => {
        return [
          ...flattened,
          ...item.c.reduce((flattenedItem, i) => {
            return [
              ...flattenedItem,
              {
                a: item.a,
                b: item.b,
                x: i.x,
                y: i.y
              }
            ]
          }, [])
        ]
      }, [])
    }
    
    console.log(flatten(list));

    【讨论】:

    猜你喜欢
    • 2020-12-22
    • 2019-07-20
    • 2018-10-24
    • 1970-01-01
    • 2020-07-11
    • 2020-09-23
    • 2017-07-02
    • 2021-10-19
    • 2012-05-29
    相关资源
    最近更新 更多