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

相关推荐
时光の尘7 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
以后不吃煲仔饭21 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师22 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者26 分钟前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
程序猿阿伟28 分钟前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
傻啦嘿哟1 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
大数据编程之光1 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
初九之潜龙勿用1 小时前
C#校验画布签名图片是否为空白
开发语言·ui·c#·.net
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
ExiFengs1 小时前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring