我很新,我现在真的很困惑.
假设我有一个坐标列表,让我说这个坐标列表中有一些双打.我不能为我的生活弄清楚如何制作一个独特的清单.通常在Python中,我可以使用集合和其他内置函数"作弊".Go中没有那么多.
package main import ( "fmt" "reflect" ) type visit struct { x, y int } func main() { var visited []visit var unique []visit visited = append(visited, visit{1, 100}) visited = append(visited, visit{2, 2}) visited = append(visited, visit{1, 100}) visited = append(visited, visit{1, 1}) unique = append(unique, visit{1, 1}) fmt.Println(unique) // Go through the visits and find the unique elements for _, v := range visited { for _, u := range unique { fmt.Printf("Here's unique: %v\n", unique) fmt.Printf("Comparing %v to %v is %v\n", v, u, reflect.DeepEqual(v, u)) if reflect.DeepEqual(v, u) { fmt.Println("Skip") } else { unique = append(unique, v) } } } fmt.Println(unique) }
Run it on Playground
您的代码中存在多个错误.最严重的是,由于您将visited
切片的每个特定元素与所有元素进行比较unique
,如果unique
包含至少一个不同的元素,您最终会附加它.如果有更多的元素unique
因为你的内部for
循环没有"中断" 而有所不同,那么你最后会多次附加它.这是不是你想要的,你要追加相等于元素没有的unique
.
另请注意,struct
如果Go中的每个字段都具有可比性,则可以比较.由于您的visit
结构只包含2个int
字段,因此它具有可比性,因此您可以visit
简单地将类型的值与=
运算符进行比较,而不需要那么难看reflect.DeepEqual()
.请参阅规范:比较运算符:
如果所有字段都具有可比性,则结构值可比较.如果相应的非空白字段相等,则两个结构值相等.
这是一个适用于您的逻辑的简化版本:
visited := []visit{ visit{1, 100}, visit{2, 2}, visit{1, 100}, visit{1, 1}, } var unique []visit for _, v := range visited { skip := false for _, u := range unique { if v == u { skip = true break } } if !skip { unique = append(unique, v) } } fmt.Println(unique)
输出(在Go Playground上试试):
[{1 100} {2 2} {1 1}]
Go确实没有内置的set类型,但你可以map[visit]bool
轻松地使用set.有了它,它变得非常简单!请注意,visit
可以在地图中用作键,因为它具有可比性(参见上文).
visited := []visit{ visit{1, 100}, visit{2, 2}, visit{1, 100}, visit{1, 1}, } unique := map[visit]bool{} for _, v := range visited { unique[v] = true } fmt.Println(unique)
输出(在Go Playground上试试):
map[{2 2}:true {1 1}:true {1 100}:true]
唯一的"列表"是地图中的键列表.
如果要将唯一visit
值作为切片,请参阅以下变体:
var unique []visit m := map[visit]bool{} for _, v := range visited { if !m[v] { m[v] = true unique = append(unique, v) } } fmt.Println(unique)
输出(正如预期的那样,在Go Playground上试试):
[{1 100} {2 2} {1 1}]
请注意,此索引表达式:m[v]
计算true
if v
是否已经在地图中(作为键,true
是我们存储在地图中的值).如果v
尚未在地图中,则为该类型m[v]
生成值类型的零值,正确地告知该值尚未在地图中.请参阅规范:索引表达式:false
bool
v
对于地图类型
M
:...如果地图是
nil
或不包含这样的条目,a[x]
则值类型为零值M