node和go的列表转树形, 执行速度测试对比

保证数据一致性,先生成4000条json数据到本地,然后分别读取文本执行处理

node代码

node是用midway框架

javascript 复制代码
  forNum1:number = 0
  forNum2:number = 0
 
 //执行测试
  async index(){
  
    // 生成菜单列表
    // const menuList = await this.generateMenuList([], 4000);

   const menuListStr = 	fs.readFileSync(this.app.getAppDir()+'/public/listJson.txt', 'utf8');
   const menuList = JSON.parse(menuListStr)
    console.time("4000条 引用类型 时间:deepTree");
    await this.deepTree(menuList);
    console.log("4000条 引用类型 时间:")
    console.timeEnd("4000条 引用类型 时间:deepTree");
    console.log("循环次数",this.forNum1)
    // this.logger.info("deepTree 数据", JSON.stringify(l));


    console.time("4000条 递归 时间:deepTree2");
    await this.deepTree2(menuList, null);
    console.timeEnd("4000条 递归 时间:deepTree2");
    console.log("循环次数",this.forNum2)

  }

  // 列表转树形
  async deepTree(list: any[]){
    const newList: any[] = [];
    const map: any = {};
    for (let index = 0; index < list.length; index++) {
      this.forNum1++
      const e = list[index];
      map[e.id] = e;
    }

    for (let index = 0; index < list.length; index++) {
      this.forNum1++
      const e = list[index];
      const parent = map[e.parentId];

      if (parent) {
        (parent.children || (parent.children = [])).push(e);
      } else {
        newList.push(e);
      }
    }
    return newList;
  }

  // 递归遍历
  async deepTree2(arr: any[], parentId: any) {
    // const loop = (parentId: any) => {
    //   return arr.reduce((pre, cur) => {
    //     this.forNum2++
    //     if (cur.parentId == parentId) {
    //       cur.children = loop(cur.id);
    //       pre.push(cur);
    //     }
    //     return pre;
    //   }, []);
    // }
    const list = []
    const loop = (parentId: any)=>{
      for (let index = 0; index < arr.length; index++) {
        this.forNum2++
        if (arr[index].parentId == parentId) {
          arr[index].children = loop(arr[index].id);
          list.push(arr[index]);
        }
      }
      return list
    }
    return loop(parentId);
  }

  //生成随机的菜单列表数据,给转换树形菜单使用
  async generateMenuList(
    menuList: { id: number; parentId: number | null }[] = [],
    maxDepth: number = 5
  ){
    // 如果菜单列表长度达到1000,则停止生成
    if (menuList.length > maxDepth || menuList.length >= 10000) {
      return menuList;
    }

    const nextID = menuList.length + 1
    // 如果菜单列表不为空,则随机选择一个已存在的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:nextID, parentId });

    // 递归调用生成子菜单项,深度加1
    return this.generateMenuList( menuList, maxDepth);
  }

测试结果

go代码

go框架是goframe

go 复制代码
var (
	ctx     context.Context
	forNum1 = 0
	forNum2 = 0
)

type MenuItem struct {
	ID       *int        `json:"id"`       // 节点的唯一标识符
	ParentId *int        `json:"parentId"` // 父节点的ID
	Children []*MenuItem `json:"children"` // 子节点列表
}
// 遍历树
func DeepTree(strSlice []*MenuItem) interface{} {
	var (
		strMap  = make(map[int]*MenuItem)
		newList []*MenuItem
	)

	for i := range strSlice {
		node := strSlice[i]
		strMap[*node.ID] = node
		forNum1++
	}
	for i := range strSlice {

		node := strSlice[i]
		if *node.ParentId != 0 {
			strMap[*node.ParentId].Children = append(strMap[*node.ParentId].Children, node)
		} else {
			newList = append(newList, node)
		}
		forNum1++
	}

	return newList
}

// 执行递归
func DeepTree2(strSlice []*MenuItem, parentId int) interface{} {
	var (
		loop func([]*MenuItem, int) []*MenuItem
		list []*MenuItem
	)
	loop = func(strSlice []*MenuItem, parentId int) []*MenuItem {
		for i := range strSlice {
			forNum2++
			if parentId == 0 {
				if *(strSlice[i].ParentId) == 0 {
					strSlice[i].Children = loop(strSlice, *(strSlice[i].ID))
					list = append(list, strSlice[i])
				}
			} else if *(strSlice[i].ParentId) != 0 && *(strSlice[i].ParentId) == parentId {
				strSlice[i].Children = loop(strSlice, *(strSlice[i].ID))
				list = append(list, strSlice[i])
			}

		}
		return list
	}
	return loop(strSlice, parentId)
}

// 生成随机菜单列表数据
func generateMenuList(menuList []*MenuItem, maxDepth int) []*MenuItem {
	// 如果菜单列表长度达到10000,则停止生成
	if len(menuList) >= maxDepth || len(menuList) >= 10000 {
		return menuList
	}

	nextID := len(menuList) + 1
	// 如果菜单列表不为空,则随机选择一个已存在的id作为parentId;否则parentId为nil
	var parentId int
	if len(menuList) > 0 {
		existingItem := menuList[rand.Intn(len(menuList))]
		parentId = *(existingItem.ID)
	}

	// 将新菜单项添加到列表中
	menuList = append(menuList, &MenuItem{ID: &nextID, ParentId: &parentId})

	// 递归调用生成子菜单项,深度加1
	return generateMenuList(menuList, maxDepth)
}

开始测试

go 复制代码
func Test(t *testing.T) {

	var (
		menuSlice []*MenuItem
	)
	//menuSlice = generateMenuList([]*MenuItem{}, 15)
	//gfile.PutContents("./listJson-15.txt", gconv.String(menuSlice))

	jsonStr := gfile.GetContents("./listJson-4000.txt")
	err := gconv.Scan(jsonStr, &menuSlice)
	if err != nil {
		return
	}

	startTime1 := time.Now()
	DeepTree(menuSlice)
	endTime1 := time.Now()
	logInfo1 := fmt.Sprintf("\n %d条 引用类型 时间:%v,循环次数:%d\n--------", len(menuSlice), endTime1.Sub(startTime1), forNum1)
	g.Log().Debug(ctx, logInfo1)

	startTime2 := time.Now()
	DeepTree2(menuSlice)
	endTime2 := time.Now()
	logInfo2 := fmt.Sprintf("\n %d条 引用类型 时间:%v,循环次数:%d\n--------", len(menuSlice), endTime2.Sub(startTime2), forNum2)
	g.Log().Debug(ctx, logInfo2)

}

测试结果:

测试连续10次的数据

相关推荐
小阮的学习笔记3 分钟前
Vue3中使用LogicFlow实现简单流程图
javascript·vue.js·流程图
YBN娜3 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=3 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
杨荧6 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰12 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
王俊山IT24 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。27 分钟前
c++多线程
java·开发语言
小政爱学习!28 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。34 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼40 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui