我想知道如何将set struct实现为地图值

时间:2018-11-16 03:19:45

标签: go

我想将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

但是,我不知道该怎么办。我应该使用其他地图吗?

有什么好主意吗?

3 个答案:

答案 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() {}

游乐场:https://play.golang.org/p/48fVQcvp3sW

答案 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 valuestruct{}在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