我想将set用作golang上的地图值。所以我这样编码:
import (
"fmt"
"reflect"
)
type TestSet struct {
Items []Test
}
func (ts *TestSet) Add(t *Test) {
ok := true
for _, item := range ts.Items {
if item.Equal(t) {
ok = false
break
}
}
if ok {
ts.Items = append(ts.Items, *t)
}
}
type Test struct {
phoneNumber string
name string
friends []string // i add this field! (**edit**)
}
func (t *Test) Equal(t2 *Test) bool {
if t.phoneNumber != t2.phoneNumber || t.name != t2.name {
return false
}
if !reflect.DeepEqual(t.friends, t2.friends) {
return false
}
return true
}
我想使用如下代码所示的结构:
val := make(map[int]*TestSet)
val[1] = &TestSet{}
val[1].Add(&Test{phoneNumber: "8210", name: "minji", friends: []string{"myself"})
但是,我的TestSet
总是必须遍历整个项目才能体现其价值。因此Add()
时间复杂度O(n)。
我想将时间复杂度降低到O(1)。 (例如 python set in
)
但是,我不知道该怎么办。我应该使用其他地图吗?
有什么好主意吗?
答案 0 :(得分:0)
也许是这样的:
package main
type Test struct {
phoneNumber string
name string
}
type TestSet struct {
Items map[string]bool
}
func (ts *TestSet) Add(t *Test) {
ts.Items[t.phoneNumber+"\x80"+t.name] = true
}
func main() {}
答案 1 :(得分:0)
通过将值类型设置为struct{}
,可以使用映射在golang中模拟集合。您的Test
结构的一些示例代码:
package main
import "fmt"
type TestSet map[Test]struct{}
func (ts TestSet) Add(t Test) {
ts[t] = struct{}{}
}
type Test struct {
phoneNumber string
name string
}
func main() {
ts := TestSet{}
t1 := Test{"a", "b"}
t2 := Test{"a", "b"}
ts.Add(t1)
ts.Add(t2)
fmt.Println(ts) // Output: map[{a b}:{}]
}
这与您的函数签名不完全匹配,因为我使用值而不是引用。这意味着我不必像您一样定义自定义Equals
函数。另外,通过将参数作为值传入,地图检查结构本身是否相等,而不是引用。
要注意的一点是,仅当结构可比较时,此方法才有效。在StackOverflow answer中引用了更多信息。
答案 2 :(得分:0)
Sets are often implemented as maps with no value。 struct{}
在Go中实际上是空的。
type Empty struct {}
type TestSet struct {
set map[Test]Empty
}
要使其正常工作,Test
必须为comparable。
如果所有字段的字段都可比较,则结构值可比较。如果两个结构值对应的非空白字段相等,则它们相等。
所以Test
是可比的。
package main;
import (
"fmt"
)
type Empty struct {}
type TestSet struct {
set map[Test]Empty
}
func (ts *TestSet) Add(t Test) bool {
if _, present := ts.set[t]; present {
return false
} else {
ts.set[t] = Empty{}
return true
}
}
type Test struct {
phoneNumber string
name string
}
func main() {
set := TestSet{ set: make(map[Test]Empty) }
test1 := Test{ phoneNumber: "555-555-5555", name: "Yarrow Hock" }
test2 := Test{ phoneNumber: "555-555-5555", name: "Yarrow Hock" }
test3 := Test{ phoneNumber: "123-555-5555", name: "Yarrow Hock" }
if set.Add( test1 ) {
fmt.Println("Added 1")
}
if set.Add( test2 ) {
fmt.Println("Added 2")
}
if set.Add( test3 ) {
fmt.Println("Added 3")
}
for test := range set.set {
fmt.Println(test.phoneNumber)
}
}
您也可以使用the golang-set library。