Go语言:优化Map创建阶段的元素出现次数统计实现
需求说明
逐词读取给定文本数据,提取宽度、高度、厚度信息,统计每组参数的出现次数,最终生成包含Quantity字段的Measurement列表用于数据库插入。现有代码可实现该功能,但写法繁琐冗余,希望获得更简洁优雅的实现方案,尤其是在对象创建耗时的场景下高效统计唯一元素出现次数。
输入数据
1190 W X 1648 H X 14 T S 1190 W X 1254 H X 14 T S 1190 W X 1254 H X 14 T S 1190 W X 1254 H X 14 T S 1190 W X 1254 H X 14 T S 1190 W X 1648 H X 14 T
现有实现代码
func CreateGlassBoxNew(db *gorm.DB, boxID uint, internalName string, glassBoxData []byte) { m := make(map[string]Measurement) var outerList []string var innerList []int var index = 0 var count = 0 var appendStr string scanner := bufio.NewScanner(strings.NewReader(string(glassBoxData))) scanner.Split(bufio.ScanWords) for scanner.Scan() { if scanner.Text() == "S" || scanner.Text() == "W" || scanner.Text() == "H" || scanner.Text() == "T" || scanner.Text() == "X" { continue } appendStr += scanner.Text() + "-" innerList = append(innerList, addMeasurementInt(scanner.Text())) index++ if index == 3 { dump.P(innerList) count++ fmt.Println(count) m[appendStr] = Measurement{ Width: innerList[0], Height: innerList[1], Thicknes: innerList[2], Quantity: count, GlassBoxID: boxID, } innerList = nil outerList = append(outerList, appendStr) appendStr = "" index = 0 } } if err := scanner.Err(); err != nil { dump.P(err) } dump.P(m) occurenceMap := CountOccurence(outerList) var finalList []Measurement for key, element := range m { finalList = append(finalList, Measurement{ Width: element.Width, Height: element.Height, Thicknes: element.Thicknes, Quantity: occurenceMap[key], GlassBoxID: boxID, }) } dump.P(finalList) }
预期插入结果
[]models.Measurement [ #len=2 models.Measurement { Width: int(1190), Height: int(1648), Thicknes: int(14), Quantity: int(2), GlassBoxID: uint(3436), BluePrintName: *string<nil>, }, models.Measurement { Width: int(1190), Height: int(1254), Thicknes: int(14), Quantity: int(4), GlassBoxID: uint(3436), BluePrintName: *string<nil>, }, ],
优化后的实现方案
import ( "bufio" "strconv" "strings" ) func CreateGlassBoxNew(db *gorm.DB, boxID uint, internalName string, glassBoxData []byte) { // 用仅包含核心参数的Measurement作为map key,直接统计出现次数 countMap := make(map[Measurement]int) scanner := bufio.NewScanner(strings.NewReader(string(glassBoxData))) scanner.Split(bufio.ScanWords) var currentMeas Measurement paramIdx := 0 for scanner.Scan() { word := scanner.Text() // 跳过无关标记字符 if word == "S" || word == "W" || word == "H" || word == "T" || word == "X" { continue } val, err := strconv.Atoi(word) if err != nil { dump.P(err) continue } // 按顺序赋值宽、高、厚 switch paramIdx { case 0: currentMeas.Width = val case 1: currentMeas.Height = val case 2: currentMeas.Thicknes = val // 三个参数收集完成,更新计数 countMap[currentMeas]++ // 重置状态 paramIdx = -1 currentMeas = Measurement{} } paramIdx++ } if err := scanner.Err(); err != nil { dump.P(err) } // 转换为最终的插入列表 var finalList []Measurement for coreMeas, quantity := range countMap { finalList = append(finalList, Measurement{ Width: coreMeas.Width, Height: coreMeas.Height, Thicknes: coreMeas.Thicknes, Quantity: quantity, GlassBoxID: boxID, }) } dump.P(finalList) // 执行数据库插入:db.Create(&finalList) } // Measurement结构体需保证核心字段为可比较类型(int/uint默认支持) type Measurement struct { Width int Height int Thicknes int Quantity int GlassBoxID uint BluePrintName *string }
优化说明
- 减少冗余操作:直接用包含宽/高/厚的
Measurement作为map key,省去原代码中生成字符串key、维护统计列表的步骤,一次遍历完成数据收集与计数。 - 提升性能:避免重复创建
Measurement对象,仅在生成最终插入列表时创建完整对象,适合对象初始化耗时的场景。 - 逻辑简化:去掉多个临时变量,流程更清晰,降低维护成本。
内容的提问来源于stack exchange,提问作者JonB
相关产品推荐
相关产品推荐

