将 Objects 的数组转换为 Objects 的分组数组
Convert array of Objects into a grouped array of Objects Typescript
我正在尝试像这样转换 objects 的数组:
[{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' }]
}
]
}
]
这个Thread和我想要的很像,但又不完全。
children 永远是唯一的,但是 parents 可以有多个 grandparents.
老实说,我已经尝试了很多东西,我什至不确定应该包括哪一个作为让我最接近的例子。
类似这样的东西,但能够接收 Objects 的数组,并抽出 {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"]}
在不对类型过于痴迷的情况下,我会说您希望输出具有以下形状:
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
的数组字典中,其中每个元素 d
进入 objMap
的键 [=20] =](如果 key
是 "grandParentField"
,则第一个元素进入名为 "grandParent1"
的键)。
完成此分组后,我们通过遍历 objMap
的键 return 一个新数组。如果我们没有 otherKeys
,我们只是 return 一个 {text: string}
元素的数组,使用 objMap
的键作为 text
字段。如果我们 do 有其他键,那么我们需要递归调用 group()
存储在 objMap
中适当键的元素。
您可以验证这是否适用于您的示例:
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"
}
]
}
]
}
] */
递归方法,应该适用于您将提供的每个 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; }
我正在尝试像这样转换 objects 的数组:
[{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' }]
}
]
}
]
这个Thread和我想要的很像,但又不完全。
children 永远是唯一的,但是 parents 可以有多个 grandparents.
老实说,我已经尝试了很多东西,我什至不确定应该包括哪一个作为让我最接近的例子。
类似这样的东西,但能够接收 Objects 的数组,并抽出 {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"]}
在不对类型过于痴迷的情况下,我会说您希望输出具有以下形状:
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
的数组字典中,其中每个元素 d
进入 objMap
的键 [=20] =](如果 key
是 "grandParentField"
,则第一个元素进入名为 "grandParent1"
的键)。
完成此分组后,我们通过遍历 objMap
的键 return 一个新数组。如果我们没有 otherKeys
,我们只是 return 一个 {text: string}
元素的数组,使用 objMap
的键作为 text
字段。如果我们 do 有其他键,那么我们需要递归调用 group()
存储在 objMap
中适当键的元素。
您可以验证这是否适用于您的示例:
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"
}
]
}
]
}
] */
递归方法,应该适用于您将提供的每个 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; }