在 Go 切片或数组中查找唯一项
Finding Unique Items in a Go Slice or Array
我还很陌生,现在我真的、真的很困惑。
假设我有一个坐标列表,假设我在这个坐标列表中有一些双打。我这辈子都想不出如何制作一份独特的清单。通常在 Python 中,我可以 "cheat" 使用集合和其他内置函数。在 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)
}
您的代码中存在多个错误。最严重的是,由于您将 visited
切片的每个特定元素与 unique
的元素的 所有 进行比较,如果unique
至少包含一个不同的。往后,如果 unique
中有更多元素,您最终将多次追加它,因为您的内部 for
循环没有 "break"。这不是您想要的,您想要追加等于 none of unique
.
的元素
另请注意,如果每个字段都具有可比性,则 Go 中的 struct
是可比的。由于您的 visit
结构仅包含 2 个 int
字段,因此它是可比较的,因此您可以简单地使用 ==
运算符比较 visit
类型的值,不需要那么丑陋的 reflect.DeepEqual()
。见 Spec: Comparison operators:
Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.
这是应用您的逻辑的简化、正确的版本:
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 确实没有内置的集合类型,但您可以轻松地将 map[visit]bool
用作集合。有了它,它变得非常简单!请注意,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]
唯一的"list"是映射中的键列表。
如果您希望将唯一的 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}]
请注意,如果 v
已经在映射中,则此索引表达式:m[v]
的计算结果为 true
(作为键,true
是我们存储的值地图)。如果 v
还不在映射中,m[v]
产生值类型的零值,对于类型 bool
是 false
,正确地告诉值 v
尚未在地图中。见 Spec: Index expressions:
For a of map type M
:
...if the map is nil
or does not contain such an entry, a[x]
is the zero value for the value type of M
我认为您可以进行 map 次访问。
像这样
visited := make(map[visit]Boolean)
你可以设置访问的值。
visited[visit]=true
最后,您可以通过此代码获取所有访问过的位置
for k, _ := range visited {
unique = append(unique, k)
}
我想你可以借助地图的帮助来解决这个难题
https://play.golang.org/p/b7JtHYQ3N8
package main
import (
"fmt"
)
type visit struct {
x, y int
}
func main() {
var visited []visit
var unique []visit
uniqueMap := map[visit]int{}
visited = append(visited, visit{1, 100})
visited = append(visited, visit{2, 2})
visited = append(visited, visit{1, 100})
visited = append(visited, visit{1, 1})
for _, v := range visited {
if _, exist := uniqueMap[v]; !exist {
uniqueMap[v] = 1
unique = append(unique, v)
} else {
uniqueMap[v]++
}
}
fmt.Printf("Uniques: %v\nMaps:%v\n", unique, uniqueMap)
}
我还很陌生,现在我真的、真的很困惑。
假设我有一个坐标列表,假设我在这个坐标列表中有一些双打。我这辈子都想不出如何制作一份独特的清单。通常在 Python 中,我可以 "cheat" 使用集合和其他内置函数。在 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)
}
您的代码中存在多个错误。最严重的是,由于您将 visited
切片的每个特定元素与 unique
的元素的 所有 进行比较,如果unique
至少包含一个不同的。往后,如果 unique
中有更多元素,您最终将多次追加它,因为您的内部 for
循环没有 "break"。这不是您想要的,您想要追加等于 none of unique
.
另请注意,如果每个字段都具有可比性,则 Go 中的 struct
是可比的。由于您的 visit
结构仅包含 2 个 int
字段,因此它是可比较的,因此您可以简单地使用 ==
运算符比较 visit
类型的值,不需要那么丑陋的 reflect.DeepEqual()
。见 Spec: Comparison operators:
Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.
这是应用您的逻辑的简化、正确的版本:
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 确实没有内置的集合类型,但您可以轻松地将 map[visit]bool
用作集合。有了它,它变得非常简单!请注意,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]
唯一的"list"是映射中的键列表。
如果您希望将唯一的 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}]
请注意,如果 v
已经在映射中,则此索引表达式:m[v]
的计算结果为 true
(作为键,true
是我们存储的值地图)。如果 v
还不在映射中,m[v]
产生值类型的零值,对于类型 bool
是 false
,正确地告诉值 v
尚未在地图中。见 Spec: Index expressions:
For a of map type
M
:...if the map is
nil
or does not contain such an entry,a[x]
is the zero value for the value type ofM
我认为您可以进行 map 次访问。 像这样
visited := make(map[visit]Boolean)
你可以设置访问的值。
visited[visit]=true
最后,您可以通过此代码获取所有访问过的位置
for k, _ := range visited {
unique = append(unique, k)
}
我想你可以借助地图的帮助来解决这个难题
https://play.golang.org/p/b7JtHYQ3N8
package main
import (
"fmt"
)
type visit struct {
x, y int
}
func main() {
var visited []visit
var unique []visit
uniqueMap := map[visit]int{}
visited = append(visited, visit{1, 100})
visited = append(visited, visit{2, 2})
visited = append(visited, visit{1, 100})
visited = append(visited, visit{1, 1})
for _, v := range visited {
if _, exist := uniqueMap[v]; !exist {
uniqueMap[v] = 1
unique = append(unique, v)
} else {
uniqueMap[v]++
}
}
fmt.Printf("Uniques: %v\nMaps:%v\n", unique, uniqueMap)
}