在Golang中设置数据结构


69

我真的很喜欢google golang,但是有人可以解释一下实现者遗漏了基本数据结构(如标准库中的集合)的基本原理吗?


8
该语言实际上称为Go,而不是golang
jozefg 2012年

92
但“golang”更是搜索
马特·

18
方式更可搜索。谷歌搜索“ go set”返回带有黑白碎片的木板图像。
Doug Richardson 2014年

Answers:


67

造成这种遗漏的一个潜在原因是,使用地图对集合进行建模非常容易。

老实说,我认为这也是一个疏忽,但是看看Perl,故事是完全一样的。在Perl中,您可以获得列表和哈希表;在Go中,您可以获得数组,切片和映射。在Perl中,通常将哈希表用于与集合有关的所有问题,这同样适用于Go。

为了模仿Go中的set int,我们定义了一个地图:

set := make(map[int]bool)

添加一些东西很容易:

i := valueToAdd()
set[i] = true

删除东西只是

delete(set, i)

而且此构造的潜在尴尬很容易抽象出来:

type IntSet struct {
    set map[int]bool
}

func (set *IntSet) Add(i int) bool {
    _, found := set.set[i]
    set.set[i] = true
    return !found   //False if it existed already
}

和delete和get可以类似地定义,我在这里有完整的实现。这里的主要缺点是go没有泛型。但是,interface{}在这种情况下可以执行get结果。


3
这是我使用“包含”和“大小”方法稍作修改的版本:play.golang.org/p/tDdutH672-
Rick-777

19
代替map[int]bool一个可以map[int]struct{}代替。我更喜欢最后一个。
pepper_chico

20
map[int]struct{}.. struct{}占用0个字节。
Boopathi Rajaa 2013年

2
github.com/fatih/set是我基于地图和空结构的实现。它是线程安全的,并且具有简单的api。
法提赫·阿尔斯兰

6
map[int]struct{}您不能if mymap["key"] {检查成员身份。Google 建议使用bool(搜索“可以实施的集”)。
Timmmm 2015年

3

我认为这与golang简单性有关。setŝ成为真正有用的differenceintersectionunionissubset,等..方法。也许golang团队认为对于一个数据结构来说太多了。但除此之外,“哑集”,只有拥有addcontains并且remove可以很容易被复制map的@jozefg作为解释。


我不同意。一个集合主要用于成员资格检查和唯一性语义。如果没有这些方法,则设置实现将完全可用。话虽如此,但实施起来也很简单。
Sedat Kapanoglu

2

仅当键是内置类型时,以上答案才有效。为了补充先前的答案,以下是一种实现集合的方法,该集合的元素是用户定义的类型:

package math

// types

type IntPoint struct {
    X, Y int
}

// set implementation for small number of items
type IntPointSet struct {
    slice []IntPoint 
}

// functions

func (p1 IntPoint) Equals(p2 IntPoint) bool {
    return (p1.X == p2.X) && (p1.Y == p2.Y)
}

func (set *IntPointSet) Add(p IntPoint) {
    if ! set.Contains(p) {
        set.slice = append(set.slice, p)
    }
}

func (set IntPointSet) Contains(p IntPoint) bool {
  for _, v := range set.slice {
    if v.Equals(p) {
      return true
    }
  }
  return false
}

func (set IntPointSet) NumElements() int {
    return len(set.slice)
}

func NewIntPointSet() IntPointSet {
  return IntPointSet{(make([]IntPoint, 0, 10))}
}

8
“仅当键是内置类型时才起作用”是错误的type mySet map[IntPoint]bool效果很好。映射中使用的键类型仅需要具有==!=。结构类型的相等性定义明确,您的Equals方法应为just p1 == p2
Dave

1
确实,结构的相等性是定义明确的,但是如果结构包含映射或切片作为字段,则将按引用而不是按值对它们进行比较。这可能不是您想要的。
Chaim-Leib Halbert,

1
我对这个解决方案有点问题,因为无论成员数量如何ContainsaMap[]它花费的时间都是线性的,而时间是恒定的。更好的解决方案是根据每个成员的内容在内部创建一个唯一键,并利用该map类型提供的恒定时间查询。还存在考虑缓存行为等的更快解决方案。
Chaim-Leib Halbert,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.