将对象数组转换为对象Typescript的分组数组



我正在尝试转换这样的对象数组:

[{grandParentField:'grandParent1', parentField:'parent1', childField: 'child1'},
{grandParentField:'grandParent1', parentField:'parent1', childField: 'child2'},
{grandParentField:'grandParent2', parentField:'parent1', childField: 'child3'},
{grandParentField:'grandParent2', parentField:'parent2', childField: 'child4'}]

转换成这种形式:

[
{
text: 'grandparent1',
items: [
{
text: 'parent1',
items: [{ text: 'child1' }, { text: 'child2' }]
}
]
},
{
text: 'grandparent2',
items: [
{
text: 'parent1',
items: [{ text: 'child3' }]
},
{
text: 'parent2',
items: [{ text: 'child4' }]
}
]
}

]

这个线程与我想要的类似,但不完全相同。

孩子永远是独一无二的,但父母可以有多个祖父母。

老实说,我已经尝试了很多东西,我甚至不确定该把哪一个作为最接近我的例子。

类似这样的东西,但能够接收一组对象,并输出{text: string, items:[{text: string, items:[{text:string]]}结构:

var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
console.log(groupBy(['one', 'two', 'three'], 'length'));
// => {3: ["one", "two"], 5: ["three"]}

递归方法应该适用于您将提供的每个n嵌套输入:

const input =[{grandParentField:"grandParent1",parentField:"parent1",childField:"child1"},{grandParentField:"grandParent1",parentField:"parent1",childField:"child2"},{grandParentField:"grandParent2",parentField:"parent1",childField:"child3"},{grandParentField:"grandParent2",parentField:"parent2",childField:"child4"}];

const nestedGroupBy = (nodes, order, orderIdx = 0) => {
const key = order[orderIdx]
let grouped = nodes.reduce((acc, e, i) => {
let node = acc.find(x => x.text == e[key])
if (!node) {
node = { text: e[key], items: [] }
acc.push(node)
}
node.items ? node.items.push(e) : node.items = [e]
return acc
}, [])
if (order[orderIdx + 1])
grouped = grouped.map(e => ({
text: e.text,
items: nestedGroupBy(e.items, order, orderIdx + 1)
}))
else
grouped = grouped.map(e => ({ text: e.text }) )
return grouped
}

const res = nestedGroupBy(input, Object.keys(input[0]))
console.log(res)
.as-console-wrapper { max-height: 100% !important; top: 0; }

在不太喜欢类型的情况下,我想说你希望你的输出是这样的:

interface Tree {
text: string,
items?: Tree[]
}

因此,让我们制作一个名为group()的函数,该函数接受您的数组和要按处理顺序处理的键的列表。因此,对于您的示例,它将像这样使用:

const data = [
{ grandParentField: 'grandParent1', parentField: 'parent1', childField: 'child1' },
{ grandParentField: 'grandParent1', parentField: 'parent1', childField: 'child2' },
{ grandParentField: 'grandParent2', parentField: 'parent1', childField: 'child3' },
{ grandParentField: 'grandParent2', parentField: 'parent2', childField: 'child4' }
];

const groupedData = group(data, "grandParentField", "parentField", "childField");

以下是group():的实现

function group(data: Array<Record<string, string>>, key: string, ...otherKeys: string[]): Tree[] {
const objMap: Record<string, any[]> = {}
for (const d of data) {
if (!(d[key] in objMap)) {
objMap[d[key]] = []
}
objMap[d[key]].push(d);
}
return Object.keys(objMap).map(k => otherKeys.length ?
{
text: k,
items: group(objMap[k], otherKeys[0], ...otherKeys.slice(1))
} : {
text: k
}
);
}

首先,我们将data中的元素分组到一个名为objMap的数组字典中,其中每个元素dd[key]处进入objMap的关键字(因此,如果key"grandParentField",则第一个元素进入名为"grandParent1"的关键字(。

完成此分组后,我们通过遍历objMap的键来返回一个新数组。如果我们没有otherKeys,我们只使用objMap的键作为text字段返回一个{text: string}元素的数组。如果确实有其他键,那么我们需要在objMap中存储的元素上以适当的键递归调用group()

您可以验证这是否适用于您的示例:

console.log(JSON.stringify(groupedData, undefined, 2));
/* [
{
"text": "grandParent1",
"items": [
{
"text": "parent1",
"items": [
{
"text": "child1"
},
{
"text": "child2"
}
]
}
]
},
{
"text": "grandParent2",
"items": [
{
"text": "parent1",
"items": [
{
"text": "child3"
}
]
},
{
"text": "parent2",
"items": [
{
"text": "child4"
}
]
}
]
}
] */

游乐场链接到代码

最新更新