Golang中如何对切片中的切片进行去重
Golang中如何对切片中的切片进行去重 大家好,
希望这个主题没问题。如果不合适,请随时删除。
我是Go语言的新手,主要是想学习。我写了一些代码(我认为)可以工作,但我对其他方法和建设性的反馈很感兴趣。特别是不使用反射的方法。
问题:
我有一个字符串切片的切片,其中存在多个重复的切片。我需要返回一个去除了重复项的、唯一的切片切片。我尝试不使用反射来实现,但这让我头大。
提前感谢任何指点/建议/评论。
(我没有看到预览按钮,如果格式有问题,我可能会编辑此内容)
代码:
package main
import (
"fmt"
"reflect"
)
func main() {
// 这些数据都将来自XML导入,我只是在模拟我将看到的数据类型
jb := []string{"James", "Bond"}
mp := []string{"Mrs", "Money", "Penny"}
xp := []string{"Mr", "Q"}
// 这是目标唯一切片中已存在的数据,应该保留
us := []string{"Im", "unique", "leave", "me", "here"}
// 创建我们的切片切片。包含许多我们想要移除的重复项。
duplicateSlices := [][]string{jb, mp, mp, jb, mp, jb, mp, jb, xp, xp, xp, jb, mp}
// 这个切片应该包含唯一的条目,加上原始值
uniqueSlices := [][]string{us}
for x := range duplicateSlices {
match := false
for y := range uniqueSlices {
if (reflect.DeepEqual(duplicateSlices[x], uniqueSlices[y])) == false {
match = false
} else {
match = true
break
}
}
if match == false {
uniqueSlices = append(uniqueSlices, duplicateSlices[x])
}
}
fmt.Println(uniqueSlices)
}
更多关于Golang中如何对切片中的切片进行去重的实战教程也可以访问 https://www.itying.com/category-94-b0.html
谢谢肖恩,这说得通!我没想到可以把“两个字符串是否相等”的判断放到一个函数里去处理。我之前试图在一个代码块里完成所有事情,结果把自己搞糊涂了。
也谢谢你的循环小技巧 🙂
更多关于Golang中如何对切片中的切片进行去重的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好,@joe19,你是在问是否可以不使用反射,从而移除对 reflect.DeepEqual 的调用吗?如果是这样,并且你只处理 []string 类型的切片,那么你可以这样做:
func stringsEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, x := range a {
if x != b[i] {
return false
}
}
return true
}
我还想说,你的循环可以简化:
exists := false
for y := range uniqueSlices {
exists = reflect.DeepEqual(duplicateSlices[x], uniqueSlices[y])
if exists {
break
}
}
if !exists {
uniqueSlices = append(uniqueSlices, duplicateSlices[x])
}
}
可以使用 map[string]struct{} 配合自定义键生成函数来实现切片去重,避免使用反射。这里提供两种实现方案:
方案一:使用字符串连接作为键
package main
import (
"fmt"
"strings"
)
func deduplicateSlices(slices [][]string) [][]string {
seen := make(map[string]struct{})
result := make([][]string, 0, len(slices))
for _, slice := range slices {
// 使用分隔符连接字符串作为键
key := strings.Join(slice, "|")
if _, exists := seen[key]; !exists {
seen[key] = struct{}{}
result = append(result, slice)
}
}
return result
}
func main() {
jb := []string{"James", "Bond"}
mp := []string{"Mrs", "Money", "Penny"}
xp := []string{"Mr", "Q"}
us := []string{"Im", "unique", "leave", "me", "here"}
duplicateSlices := [][]string{jb, mp, mp, jb, mp, jb, mp, jb, xp, xp, xp, jb, mp}
// 包含原始唯一切片
allSlices := append([][]string{us}, duplicateSlices...)
uniqueSlices := deduplicateSlices(allSlices)
fmt.Println(uniqueSlices)
}
方案二:使用更安全的键生成方法
package main
import (
"fmt"
"strconv"
)
func sliceToKey(slice []string) string {
var builder strings.Builder
builder.WriteString(strconv.Itoa(len(slice)))
for _, s := range slice {
builder.WriteByte('|')
builder.WriteString(strconv.Itoa(len(s)))
builder.WriteByte(':')
builder.WriteString(s)
}
return builder.String()
}
func deduplicateSlicesSafe(slices [][]string) [][]string {
seen := make(map[string]struct{})
result := make([][]string, 0, len(slices))
for _, slice := range slices {
key := sliceToKey(slice)
if _, exists := seen[key]; !exists {
seen[key] = struct{}{}
result = append(result, slice)
}
}
return result
}
func main() {
jb := []string{"James", "Bond"}
mp := []string{"Mrs", "Money", "Penny"}
xp := []string{"Mr", "Q"}
us := []string{"Im", "unique", "leave", "me", "here"}
duplicateSlices := [][]string{jb, mp, mp, jb, mp, jb, mp, jb, xp, xp, xp, jb, mp}
// 包含原始唯一切片
allSlices := append([][]string{us}, duplicateSlices...)
uniqueSlices := deduplicateSlicesSafe(allSlices)
fmt.Println(uniqueSlices)
}
方案三:通用泛型实现(Go 1.18+)
package main
import (
"fmt"
"strconv"
"strings"
)
func Deduplicate[T comparable](slices [][]T) [][]T {
seen := make(map[string]struct{})
result := make([][]T, 0, len(slices))
for _, slice := range slices {
var keyBuilder strings.Builder
keyBuilder.WriteString(strconv.Itoa(len(slice)))
for _, v := range slice {
keyBuilder.WriteByte('|')
fmt.Fprintf(&keyBuilder, "%v", v)
}
key := keyBuilder.String()
if _, exists := seen[key]; !exists {
seen[key] = struct{}{}
result = append(result, slice)
}
}
return result
}
func main() {
jb := []string{"James", "Bond"}
mp := []string{"Mrs", "Money", "Penny"}
xp := []string{"Mr", "Q"}
us := []string{"Im", "unique", "leave", "me", "here"}
duplicateSlices := [][]string{jb, mp, mp, jb, mp, jb, mp, jb, xp, xp, xp, jb, mp}
allSlices := append([][]string{us}, duplicateSlices...)
uniqueSlices := Deduplicate(allSlices)
fmt.Println(uniqueSlices)
}
这些方法都不需要使用反射,通过将切片转换为唯一的字符串键来实现去重。方案二通过包含长度信息来避免分隔符冲突,是最安全的选择。

