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次的数据

相关推荐
264玫瑰资源库43 分钟前
问道数码兽 怀旧剧情回合手游源码搭建教程(反查重优化版)
java·开发语言·前端·游戏
普if加的帕1 小时前
java Springboot使用扣子Coze实现实时音频对话智能客服
java·开发语言·人工智能·spring boot·实时音视频·智能客服
拉不动的猪1 小时前
前端自做埋点,我们应该要注意的几个问题
前端·javascript·面试
安冬的码畜日常2 小时前
【AI 加持下的 Python 编程实战 2_10】DIY 拓展:从扫雷小游戏开发再探问题分解与 AI 代码调试能力(中)
开发语言·前端·人工智能·ai·扫雷游戏·ai辅助编程·辅助编程
烛阴2 小时前
Node.js中必备的中间件大全:提升性能、安全与开发效率的秘密武器
javascript·后端·express
小杨升级打怪中2 小时前
前端面经-JS篇(三)--事件、性能优化、防抖与节流
前端·javascript·xss
朝阳5812 小时前
Rust项目GPG签名配置指南
开发语言·后端·rust
朝阳5812 小时前
Rust实现高性能目录扫描工具ll的技术解析
开发语言·后端·rust
程高兴2 小时前
基于Matlab的车牌识别系统
开发语言·matlab
牛马baby3 小时前
Java高频面试之并发编程-07
java·开发语言·面试