Golang统计字符频次后如何按原索引顺序输出结果
问题背景
需求规则:输入任意字符串,输出结果需遵循两个规则:
- 按字符在原字符串中首次出现的顺序拼接内容
- 每个字符仅在首次出现位置展示:字符本身 + 该字符在全串的总出现频次,若频次为1则省略频次数字
示例:输入input := "programming"时,预期输出output := "p2ro2ga2min"。
现有实现问题:通过map存储字符计数值的逻辑是正确的,但Go语言中map遍历顺序是随机无序的,直接遍历map输出会完全打乱原字符串的字符顺序,当前代码输出为n1p1r2o1g2a1m2i1,不符合顺序要求,也未处理频次为1时省略数字的逻辑。
解决思路
核心是绕开map无序的特性,不要直接遍历map生成结果:
- 第一步:保留原有map统计频次的逻辑,先遍历一次全串,拿到每个字符的总出现次数
- 第二步:新增一个辅助集合,记录已经输出过的字符,避免同一个字符重复拼接频次
- 第三步:直接遍历原始字符串(遍历顺序就是原索引顺序,完全匹配输出要求的顺序),遇到未输出过的字符时,拼接字符本身;如果该字符总频次大于1,再拼接对应的频次数字,之后把字符标记为已输出;遇到已经输出过的字符直接跳过即可。
修正后代码
package main import ( "fmt" "strings" ) func buildResult(s string) string { // 统计每个字符的总出现频次 freqMap := make(map[rune]int) for _, c := range s { freqMap[c]++ } var builder strings.Builder // 记录已经完成输出的字符,避免重复拼接 printed := make(map[rune]bool) // 按原字符串顺序遍历,而非遍历无序的map for _, c := range s { if printed[c] { continue } // 拼接字符本身 builder.WriteRune(c) // 频次大于1才拼接数字,频次为1时省略 if freqMap[c] > 1 { builder.WriteString(fmt.Sprintf("%d", freqMap[c])) } printed[c] = true } return builder.String() } func main() { input := "programming" output := buildResult(input) fmt.Println(output) }
关键说明
- 遍历原始字符串的顺序就是字符首次出现的索引顺序,从根源上解决了map无序导致的顺序错乱问题
- 用
strings.Builder做字符串拼接比直接用+拼接性能更好,尤其是字符串较长时优势明显 - 辅助map
printed的作用是去重,确保每个字符的频次只在第一次出现时输出一次,不会重复拼接 - 代码中用
rune类型处理字符,可以兼容中文等多字节字符,不会出现编码乱码问题
内容的提问来源于stack exchange,提问作者adrian sitorus
相关产品推荐
相关产品推荐

