JavaScript嵌套对象展开

4
我有一个嵌套对象,想要将其展开/映射成为一个单层的、类似于表格的对象。
[{
    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循环很快变得混乱不堪。

1
你在这里并不是很出色,因为如果是这样的话,你会有重复的x和y。此外,这个结构总是这样吗?如果{x,y}有另一个子数组,那么这个乘法会更多吗? - Keith
1
@Brewal 绝对不是一个适合在代码评审中提出的问题。 - Teemu
@Brewal 在我的实际代码中,不仅有两层,而是四层。如果我尝试在那里使用for循环方法,它会变得非常丑陋。 - André Reichelt
1
@Brewal 但是他们正在修复现有的和工作的代码,当在codereview中没有任何代码时,那里的回答甚至比这里更难。 - Teemu
1
@Teemu 我假设已经有一个可行的解决方案了。 - Brewal
显示剩余9条评论
5个回答

5
你可以在属性'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);


1
感谢您提供解决方案。您的解决方案似乎与Bergi的想法完全相同。我已经创建了一个jsperf:https://jsperf.com/unfold-complex-object/1 - André Reichelt

3
理想情况下,解决方案需要某种方式来确定何时开始将对象分类为完整对象,一个简单的解决方案就是传递您想要的级别。如果您不想传递级别,则可以进行检查,如果没有任何属性具有数组,则将其视为完整记录,但当然这种逻辑需要确认。
如果您想要一个通用版本,可以处理多个级别,并使用递归,您可以像这样做 - >

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:https://jsperf.com/unfold-complex-object/1 - André Reichelt
@AndréReichelt 这个jsperf比较并不公平,因为我的是唯一的通用解决方案 :) ,但是说它比通用解决方案慢14%似乎也不算太糟糕,所以这很有趣.. - Keith
1
我决定将你的想法标记为解决方案,因为它确实是唯一通用的方法。如果将来我更改C#类中的任何内容,这种方法需要的维护量最少。 - André Reichelt
修改您的代码以使其扁平化非数组属性会很困难吗?我的结构包含两个仅为单个对象的属性。 - André Reichelt
@AndréReichelt 我相信修改不应该太难。你能否根据这个想法提供一个示例输入/输出呢?如果需要的话,也可以将其转化为另一个问题并引用此问题。 - Keith

2
一个使用 flatMap 的解决方案如下所示:
const result = myObj.flatMap(outer =>
  outer.c.map(inner =>
    ({a: outer.a, b: outer.b, x: inner.x, y: inner.y})
  )
);

当然,如果您的对象有多个层级,而不仅仅是两个,并且可能甚至有多个或未知属性具有这样的嵌套,则应尝试实现递归解决方案。或者采用迭代方法,在属性名称数组(对于您的示例情况,["c"])上循环,并逐层应用平铺。

感谢您提供解决方案。我已经创建了一个 jsperf: https://jsperf.com/unfold-complex-object/1 - André Reichelt

2

使用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));


1
感谢您提供解决方案。我已经创建了一个jsperf:https://jsperf.com/unfold-complex-object/1 - André Reichelt

1

Using two reducers to flatten your structure

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)


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