展平嵌套 JavaScript 对象
Flatten nested JavaScript object
我有一个嵌套对象,我想 flatten/map 将它变成一个单层的 table 类对象。
[{
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
部分,但我不知道如何将 a
和 b
映射到该对象,它就可以工作。
由于你们中的一些人要求一些工作代码,这应该可以做到(未经测试):
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 循环很快变得凌乱。
使用两个减速器来扁平化你的结构
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)
flatMap
解决方案如下所示:
const result = myObj.flatMap(outer =>
outer.c.map(inner =>
({a: outer.a, b: outer.b, x: inner.x, y: inner.y})
)
);
当然,如果你的对象有多层,不只是两层,甚至可能有多个或未知的属性有这样的嵌套,你应该尝试实现一个递归的解决方案。或者一个迭代的,你循环遍历 属性 名称的数组(对于你的例子,["c"]
)并逐级应用展平。
您可以在 属性 上使用 flatMap
方法和 map
'c':
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);
理想情况下,一个解决方案需要一些东西来说明从多远开始 class将对象视为一个完整的对象,一个简单的解决方案就是通过您想要的级别。如果你不想通过关卡,你可以检查一下,如果 none 的属性有数组,那么你会 class 这是一个完整的记录,但当然逻辑是这样的你需要确认一下。
如果你想要一个适用于多个关卡的通用版本,你可以通过关卡并使用递归,你可以这样做 ->
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));
其中一个使用 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));
我有一个嵌套对象,我想 flatten/map 将它变成一个单层的 table 类对象。
[{
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
部分,但我不知道如何将 a
和 b
映射到该对象,它就可以工作。
由于你们中的一些人要求一些工作代码,这应该可以做到(未经测试):
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 循环很快变得凌乱。
使用两个减速器来扁平化你的结构
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)
flatMap
解决方案如下所示:
const result = myObj.flatMap(outer =>
outer.c.map(inner =>
({a: outer.a, b: outer.b, x: inner.x, y: inner.y})
)
);
当然,如果你的对象有多层,不只是两层,甚至可能有多个或未知的属性有这样的嵌套,你应该尝试实现一个递归的解决方案。或者一个迭代的,你循环遍历 属性 名称的数组(对于你的例子,["c"]
)并逐级应用展平。
您可以在 属性 上使用 flatMap
方法和 map
'c':
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);
理想情况下,一个解决方案需要一些东西来说明从多远开始 class将对象视为一个完整的对象,一个简单的解决方案就是通过您想要的级别。如果你不想通过关卡,你可以检查一下,如果 none 的属性有数组,那么你会 class 这是一个完整的记录,但当然逻辑是这样的你需要确认一下。
如果你想要一个适用于多个关卡的通用版本,你可以通过关卡并使用递归,你可以这样做 ->
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));
其中一个使用 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));