常见的业务场景: 无限级分类菜单、无限员工丛属关系等
难度系数: 初级
这里以golang为演示,支持引用传递或者指针数据类型的编程语言都可实现
题目
ManagerID
为父级ID,对应ID
字段,Subordinates
为children
子集,将下面数据处理成具有层级关系的结构
type Employee struct {
ID int
Name string
Salary float64
ManagerID int
Subordinates []*Employee
}
csvData := []*Employee{
{ID: 1, Name: "Alice", Salary: 100000, ManagerID: 0},
{ID: 2, Name: "Bob", Salary: 75000, ManagerID: 1},
{ID: 5, Name: "Dan", Salary: 50000, ManagerID: 2},
{ID: 10, Name: "Ian", Salary: 30000, ManagerID: 5},
{ID: 11, Name: "Jane", Salary: 30000, ManagerID: 5},
{ID: 6, Name: "Ed", Salary: 50000, ManagerID: 2},
{ID: 12, Name: "Kyle", Salary: 50000, ManagerID: 6},
}
答案
// 原始数据填充到map类型中,查询时间复杂度O1
// 注意:这里的map的v是指针类型,与原始数据的地址是一致的
employeeMap := make(map[int]*Employee)
for _, emp := range csvData {
employeeMap[emp.ID] = emp
emp.Subordinates = []*Employee{} // 初始化Subordinates
}
for _, emp := range csvData {
if emp.ManagerID != 0 { // 排除顶级员工(ManagerID为0)
if manager, ok := employeeMap[emp.ManagerID]; ok {
manager.Subordinates = append(manager.Subordinates, emp)
}
}
}
var topLevelEmployees []*Employee
for _, emp := range csvData {
if emp.ManagerID == 0 {
topLevelEmployees = append(topLevelEmployees, emp)
}
}
// 两个内存地址是一样
fmt.Println("Memory address of ePtr:", fmt.Sprintf("%p", csvData[0]))
fmt.Println("Memory address of ePtr:", fmt.Sprintf("%p", employeeMap[1]))
// 利用 json 来验证处理的数据格式
marshal, _ := json.Marshal(topLevelEmployees)
fmt.Println(string(marshal))