按 Object 从数组 Object 到树 Object Javascript 分组
Group by Object from Array Object to Tree Object Javascript
我需要像这里这样的帮助组 object:
输入数组为:
[
{
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',
AdminLevel: 4,
ParentId: '1234'
},
{
Id:'111213',
Name: 'Province - Da Nang',
AdminLevel: 4,
ParentId: '1234'
},
{
Id:'111213',
Name: 'District - Quan 1',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 2',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 3',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 1',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 2',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 3',
AdminLevel: 6,
ParentId: '91011'
}
]
并且期望 out-put 是:
{
Id: '1234',
Name: 'Country - Viet Nam',
AdminLevel: 2,
Data: [
{
Id:'5678',
Name: 'Province - Ho Chi Minh',
AdminLevel: 4,
ParentId: '1234',
Data: [
{
Id:'111213',
Name: 'District - Quan 1',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 2',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 3',
AdminLevel: 6,
ParentId: '5678'
}
]
},
{
Id:'91011',
Name: 'Province - Ha Noi',
AdminLevel: 4,
ParentId: '1234',
Data: [
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 1',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 2',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 3',
AdminLevel: 6,
ParentId: '91011'
}
]
},
{
Id:'111213',
Name: 'Province - Da Nang',
AdminLevel: 4,
ParentId: '1234'
},
]
}
说明:我们要先按AdminLevel分组,再按ParentId分组。
- 看看我们有结构:国家(Parent) - 省(多个 - Child 国家) - 地区(多个 - Child 省)。
非常感谢你帮助我
假设您的数据已排序,因此 parents 在 children 之前,这很简单:
- 遍历所有节点
- 对于每个找到 parent
- 添加到 parent 的
Data
属性(如果还没有则先创建)
- Return根节点
根节点将是没有任何 parent 的节点。您可以使用地图来跟踪访问过的项目并使查找 parent 更容易。
由于您的数据没有唯一 ID,因此您需要为每个 ID 保留一个项目数组。如果您的数据恰好有一个 parent ID 匹配两个或更多的东西,那么每个东西都会有 child 节点。
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', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'Province - Da Nang', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'District - Quan 1', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 2', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 3', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 1', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 2', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 3', AdminLevel: 6, 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);
如果您的数据未排序并且 parents 可能出现在它们的 children 之前或之后,以上代码将不起作用,因为它只访问并找到 parents 的顺序,例如,它将因 [{Id: 2, ParentId: 1}, {Id: 1}]
而失败。如果恰好是这种情况,您可以更改函数的主体以首先索引所有项目,然后 然后 将它们添加到各自的 parents:
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', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'Province - Da Nang', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'District - Quan 1', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 2', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 3', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 1', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 2', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 3', AdminLevel: 6, 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
分组是一项无关的操作,因为您不希望每个 parent.
存在多个组
见a TypeScript solution using the same algorithm courtesy of jcalz
我需要像这里这样的帮助组 object: 输入数组为:
[
{
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',
AdminLevel: 4,
ParentId: '1234'
},
{
Id:'111213',
Name: 'Province - Da Nang',
AdminLevel: 4,
ParentId: '1234'
},
{
Id:'111213',
Name: 'District - Quan 1',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 2',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 3',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 1',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 2',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 3',
AdminLevel: 6,
ParentId: '91011'
}
]
并且期望 out-put 是:
{
Id: '1234',
Name: 'Country - Viet Nam',
AdminLevel: 2,
Data: [
{
Id:'5678',
Name: 'Province - Ho Chi Minh',
AdminLevel: 4,
ParentId: '1234',
Data: [
{
Id:'111213',
Name: 'District - Quan 1',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 2',
AdminLevel: 6,
ParentId: '5678'
},
{
Id:'111213',
Name: 'District - Quan 3',
AdminLevel: 6,
ParentId: '5678'
}
]
},
{
Id:'91011',
Name: 'Province - Ha Noi',
AdminLevel: 4,
ParentId: '1234',
Data: [
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 1',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 2',
AdminLevel: 6,
ParentId: '91011'
},
{
Id:'111213',
Name: 'District - Tinh nao do Ha Noi 3',
AdminLevel: 6,
ParentId: '91011'
}
]
},
{
Id:'111213',
Name: 'Province - Da Nang',
AdminLevel: 4,
ParentId: '1234'
},
]
}
说明:我们要先按AdminLevel分组,再按ParentId分组。
- 看看我们有结构:国家(Parent) - 省(多个 - Child 国家) - 地区(多个 - Child 省)。 非常感谢你帮助我
假设您的数据已排序,因此 parents 在 children 之前,这很简单:
- 遍历所有节点
- 对于每个找到 parent
- 添加到 parent 的
Data
属性(如果还没有则先创建) - Return根节点
根节点将是没有任何 parent 的节点。您可以使用地图来跟踪访问过的项目并使查找 parent 更容易。
由于您的数据没有唯一 ID,因此您需要为每个 ID 保留一个项目数组。如果您的数据恰好有一个 parent ID 匹配两个或更多的东西,那么每个东西都会有 child 节点。
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', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'Province - Da Nang', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'District - Quan 1', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 2', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 3', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 1', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 2', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 3', AdminLevel: 6, 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);
如果您的数据未排序并且 parents 可能出现在它们的 children 之前或之后,以上代码将不起作用,因为它只访问并找到 parents 的顺序,例如,它将因 [{Id: 2, ParentId: 1}, {Id: 1}]
而失败。如果恰好是这种情况,您可以更改函数的主体以首先索引所有项目,然后 然后 将它们添加到各自的 parents:
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', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'Province - Da Nang', AdminLevel: 4, ParentId: '1234' }, { Id:'111213', Name: 'District - Quan 1', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 2', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Quan 3', AdminLevel: 6, ParentId: '5678' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 1', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 2', AdminLevel: 6, ParentId: '91011' }, { Id:'111213', Name: 'District - Tinh nao do Ha Noi 3', AdminLevel: 6, 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
分组是一项无关的操作,因为您不希望每个 parent.
见a TypeScript solution using the same algorithm courtesy of jcalz