问题描述
我需要像这样的帮助组对象: 输入数组为:
[
{
Id: '1234',Name: 'Country - Viet Nam',AdminLevel: 2
},{
Id:'5678',Name: 'Province - Ho Chi Minh',AdminLevel: 4,ParentId: '1234'
},{
Id:'91011',Name: 'Province - Ha Noi',{
Id:'111213',Name: 'Province - Da Nang',Name: 'district - Quan 1',AdminLevel: 6,ParentId: '5678'
},Name: 'district - Quan 2',Name: 'district - Quan 3',Name: 'district - Tinh nao do Ha Noi 1',ParentId: '91011'
},Name: 'district - Tinh nao do Ha Noi 2',Name: 'district - Tinh nao do Ha Noi 3',ParentId: '91011'
}
]
预计产量为:
{
Id: '1234',AdminLevel: 2,Data: [
{
Id:'5678',ParentId: '1234',Data: [
{
Id:'111213',ParentId: '5678'
},{
Id:'111213',ParentId: '5678'
}
]
},{
Id:'91011',ParentId: '91011'
},ParentId: '91011'
}
]
},{
Id:'111213',ParentId: '1234'
},]
}
说明:我们必须先按AdminLevel分组,然后再按ParentId分组。
- 别忘了我们具有以下结构:国家(父母)-省(多个-国家的孩子)-地区(多个-省的孩子)。 非常感谢您对我的帮助
解决方法
假设您的数据是有序的,那么父母先于孩子,这很简单:
- 遍历所有节点
- 为每个找到父母的人
- 添加到父级的
Data
属性(如果尚不存在,请先创建) - 返回根节点
根节点将是没有任何父节点的节点。您可以使用地图来跟踪访问的物品,并使其更容易查找父母。
由于数据没有唯一的ID,因此您需要为每个ID保留一组项目。如果您的数据碰巧具有与两个或多个事物匹配的父ID,则每个数据都将具有子节点。
const data = [ { Id: '1234',Name: 'Country - Viet Nam',AdminLevel: 2 },{ Id:'5678',Name: 'Province - Ho Chi Minh',AdminLevel: 4,ParentId: '1234' },{ Id:'91011',Name: 'Province - Ha Noi',{ Id:'111213',Name: 'Province - Da Nang',Name: 'District - Quan 1',AdminLevel: 6,ParentId: '5678' },Name: 'District - Quan 2',Name: 'District - Quan 3',Name: 'District - Tinh nao do Ha Noi 1',ParentId: '91011' },Name: 'District - Tinh nao do Ha Noi 2',Name: 'District - Tinh nao do Ha Noi 3',ParentId: '91011' } ];
function group(arr) {
let root;
//keep a reference of all elements visited
const lookup = new Map();
//go through the array
for (const item of arr) {
//add to the lookup
const key = item.Id;
const value = lookup.get(key) ?? [];
lookup.set(key,value.concat(item));
if ("ParentId" in item){
//find the parent(s) and update
lookup.get(item.ParentId)
.forEach(parent => {
parent.Data = parent.Data ?? [];
parent.Data.push(item);
});
} else {
//if the item doesn't have a parent,it's the root node
root = item;
}
}
return root;
}
const result = group(data);
console.log(result);
如果未排序您的数据,并且父母可能在孩子之前或之后出现,则上述代码将不起作用,因为它只会按顺序访问并找到父母,例如,[{Id: 2,ParentId: 1},{Id: 1}]
失败。如果是这种情况,可以将函数的主体更改为首先索引所有项目,然后然后将它们添加到各自的父项中:
const data = [ { Id: '1234',ParentId: '91011' } ];
function group(arr) {
let root;
//keep a reference of all elements visited
const lookup = new Map();
//first index all items
for (const item of arr) {
//add to the lookup
const key = item.Id;
const value = lookup.get(key) ?? [];
lookup.set(key,value.concat(item));
}
//go through the array
for (const item of arr) {
if ("ParentId" in item){
//find the parent(s) and update
lookup.get(item.ParentId)
.forEach(parent => {
parent.Data = parent.Data ?? [];
parent.Data.push(item);
});
} else {
//if the item doesn't have a parent,it's the root node
root = item;
}
}
return root;
}
const result = group(data);
console.log(result);
这仍然是O(n)
解决方案,因为它将随着输入线性增长。
请注意,这并不是按AdminLevel
进行分组,因为似乎没有必要。数据自然根据ParentId
进行分组。假设您不希望每个父级都存在多个组,那么首先按AdminLevel
进行分组是一项无关紧要的操作。
使用与a TypeScript solution相同的算法查看jcalz