Golang移除切片相同元素遇索引越界panic,求两种实现方案
问题描述
现有两个rune切片:
a := []rune("/storage/emulated/0/Custom_Scripts/Golang/") b := []rune("/storage/emulated/0/")
需求:从切片a中移除所有与切片b中元素相同的元素,仅允许引入fmt包用于打印结果,需通过两种方式实现:循环遍历、利用映射。
用户自行编写的循环实现代码触发索引越界panic,代码如下:
package main import( "fmt" ) func main() { fileMeta := []rune("/storage/emulated/0/Custom_Scripts/Golang/") delChr := []rune("/storage/emulated/0") for i, j := range fileMeta { for _, m := range delChr { if m == j { //fileMeta[i] = "" fileMeta = append(fileMeta[:i], fileMeta[i+1:]...) } } } fmt.Println(fileMeta) }
错误原因分析
你代码里的索引越界panic,根源是在遍历原切片的同时直接修改切片长度:
range fileMeta是基于切片初始长度生成的遍历序列,当你用append(fileMeta[:i], fileMeta[i+1:]...)删除元素时,切片fileMeta的长度会缩短。- 遍历到后期,原来的索引
i会超过新切片的长度,导致访问fileMeta[i+1:]时触发越界。 - 另外,即使没触发越界,删除元素后后续元素的索引会前移,继续用原来的
i遍历会跳过部分元素,逻辑也不正确。
方法一:循环遍历(创建新切片收集结果)
这种方式不修改原切片,而是创建一个新切片,只保留a中不在b里的元素:
package main import "fmt" func main() { a := []rune("/storage/emulated/0/Custom_Scripts/Golang/") b := []rune("/storage/emulated/0/") // 创建新切片存储结果,预分配原切片长度的空间提升效率 result := make([]rune, 0, len(a)) outer: for _, char := range a { // 检查当前字符是否在b中 for _, delChar := range b { if char == delChar { // 存在则跳过,继续处理下一个字符 continue outer } } // 不存在则加入结果切片 result = append(result, char) } fmt.Println(string(result)) // 输出: Custom_Scripts/Golang }
这里用outer标签跳出内层循环,避免重复判断,逻辑清晰且不会出现索引问题。
方法二:利用映射优化查询效率
当切片b的元素较多时,用映射可以将查询时间从O(n)降到O(1),大幅提升效率:
package main import "fmt" func main() { a := []rune("/storage/emulated/0/Custom_Scripts/Golang/") b := []rune("/storage/emulated/0/") // 将b中的元素存入map,键为rune,值为bool标记需删除 delMap := make(map[rune]bool) for _, char := range b { delMap[char] = true } // 遍历a,收集不在删除映射中的元素 result := make([]rune, 0, len(a)) for _, char := range a { if !delMap[char] { result = append(result, char) } } fmt.Println(string(result)) // 输出: Custom_Scripts/Golang }
这种方式先构建删除元素的映射表,再遍历原切片快速判断是否保留元素,比双重循环更高效。
内容的提问来源于stack exchange,提问作者functionX
相关产品推荐
相关产品推荐

