js代码,浏览器上运行
// 列表转树形
export function deepTree(list: any[]): any[] {
const newList: any[] = [];
const map: any = {};
for (let index = 0; index < list.length; index++) {
const e = list[index];
map[e.id] = e;
}
for (let index = 0; index < list.length; index++) {
const e = list[index];
const parent = map[e.parentId];
if (parent) {
(parent.children || (parent.children = [])).push(e);
} else {
newList.push(e);
}
}
return newList;
}
// 递归遍历
export const deepTree2 = (arr: any[], parentId: any) => {
function loop(parentId: any) {
return arr.reduce((pre, cur) => {
if (cur.parentId == parentId) {
cur.children = loop(cur.id);
pre.push(cur);
}
return pre;
}, []);
}
return loop(parentId);
};
// 遍历树
export const deepTree3 = (arr: any[]) => {
// 利用两层filter实现
let newList = arr.filter((item) => {
item.children = arr.filter((e) => {
return item.id === e.parentId;
});
return !item.parentId;
});
return newList;
};
// 树形转列表
export function revDeepTree(list: any[]) {
const arr: any[] = [];
let id = 0;
function deep(list: any[], parentId: number) {
list.forEach((e) => {
if (!e.id) {
e.id = id++;
}
if (!e.parentId) {
e.parentId = parentId;
}
arr.push(e);
if (e.children && isArray(e.children)) {
deep(e.children, e.id);
}
});
}
deep(list || [], 0);
return arr;
}
测试运行
//生成随机的菜单列表数据,给转换树形菜单使用
function generateMenuList(
depth: number = 1,
menuList: { id: number; parentId: number | null }[] = [],
maxDepth: number = 5
): { id: number; parentId: number | null }[] {
// 如果菜单列表长度达到1000,则停止生成
if (menuList.length >= 10000) {
return menuList;
}
// 如果当前深度超过了最大深度,则停止递归
if (depth > maxDepth) {
return menuList;
}
// 生成一个随机的id
let id = depth;
// 如果菜单列表不为空,则随机选择一个已存在的id作为parentId;否则parentId为null
let parentId: number | null = null;
if (menuList.length > 0) {
parentId = menuList[Math.floor(Math.random() * menuList.length)].id;
}
// 将新菜单项添加到列表中
menuList.push({ id, parentId });
// 递归调用生成子菜单项,深度加1
return generateMenuList(depth + 1, menuList, maxDepth);
}
// 生成菜单列表
const menuList = generateMenuList(1, [], 4000);
// 输出生成的菜单列表
console.log(menuList);
console.time("deepTree");
const l = deepTree(menuList);
console.log("l 引用类型", l);
console.timeEnd("deepTree");
console.time("deepTree2");
const l2 = deepTree2(menuList, null);
console.log("l2 递归", l2);
console.timeEnd("deepTree2");
console.time("deepTree3");
const l3 = deepTree3(menuList);
console.log("l3 filter循环", l3);
console.timeEnd("deepTree3");
执行结果
go代码,编辑器运行
// 遍历树
func DeepTree(strSlice []*TreeNode) interface{} {
var (
strMap = make(map[string]*TreeNode)
newList []*TreeNode
)
for i := range strSlice {
node := strSlice[i]
strMap[node.ID] = node
}
for i := range strSlice {
node := strSlice[i]
if node.ParentId != "" {
strMap[node.ParentId].Children = append(strMap[node.ParentId].Children, node)
} else {
newList = append(newList, node)
}
}
return newList
}
// 递归遍历树
func DeepTree2(strSlice []*TreeNode) interface{} {
newList := loop(strSlice, "")
return newList
}
func loop(strSlice []*TreeNode, parentId string) []*TreeNode {
var newList []*TreeNode
for i := range strSlice {
if strSlice[i].ParentId == parentId {
strSlice[i].Children = loop(strSlice, strSlice[i].ID)
newList = append(newList, strSlice[i])
}
}
return newList
}
测试运行
func Test(t *testing.T) {
var (
menuSlice []*MenuItem
strSlice []*TreeNode
)
menuSlice = generateMenu(1, menuSlice, 4000)
str := gjson.MustEncodeString(menuSlice)
gconv.Scan(str, strSlice)
startTime1 := time.Now()
DeepTree(strSlice)
endTime1 := time.Now()
g.Log().Debugf(ctx, "4000条 引用类型 时间:%v", endTime1.Sub(startTime1))
startTime2 := time.Now()
DeepTree2(strSlice)
endTime2 := time.Now()
g.Log().Debugf(ctx, "4000条 递归 时间:%v", endTime2.Sub(startTime2))
}
运行结果
最终结果:
js的第一种写法执行最快,用时 0.598876953125毫秒是 598.88 微秒
go的第一种写法执行最快,用时 83 微妙
个人测试,有错误的欢迎留言指正