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

相关推荐
香饽饽~、43 分钟前
【第十一篇】SpringBoot缓存技术
java·开发语言·spring boot·后端·缓存·intellij-idea
Devil枫2 小时前
Kotlin扩展函数与属性
开发语言·python·kotlin
菠萝加点糖2 小时前
Kotlin Data包含ByteArray类型
android·开发语言·kotlin
2301_803554523 小时前
c++中类的前置声明
java·开发语言·c++
Cacciatore->5 小时前
Electron 快速上手
javascript·arcgis·electron
vvilkim5 小时前
Electron 进程间通信(IPC)深度优化指南
前端·javascript·electron
不想写bug呀6 小时前
多线程案例——单例模式
java·开发语言·单例模式
某公司摸鱼前端6 小时前
ES13(ES2022)新特性整理
javascript·ecmascript·es13
我不会写代码njdjnssj6 小时前
网络编程 TCP UDP
java·开发语言·jvm
清幽竹客7 小时前
vue-30(理解 Nuxt.js 目录结构)
前端·javascript·vue.js