私は本当にgoogle golangが好きですが、標準ライブラリのセットなどの基本的なデータ構造を実装者が省略している理由を説明できる人がいますか?
この省略の潜在的な理由の1つは、マップを使用してセットをモデル化することが本当に簡単であることです。
正直なところ、それも少し見落としだと思いますが、Perlを見ると、まったく同じです。 Perlではリストとハッシュテーブルを取得し、Goでは配列、スライス、マップを取得します。 Perlでは通常、セットに関連するすべての問題に対してハッシュテーブルを使用しますが、Goにも同じことが当てはまります。
例
goでセットの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
}
そして、削除と取得も同様に定義できます。完全な実装 here があります。ここでの主な欠点は、goにジェネリックがないことです。ただし、interface{}
を使用してこれを行うことは可能です。その場合、getの結果をキャストします。
これは、シンプルさを重視するgolang
に関係していると思います。 set
sは、difference
、intersection
、union
、issubset
などのメソッドで本当に便利になります。おそらくgolang
チームは、1つのデータ構造では多すぎると感じました。しかし、それ以外の場合、@ jozefgで説明されているように、add
、contains
、およびremove
のみを含む「ダムセット」は、map
を使用して簡単に複製できます。
前の回答は、キーが組み込み型である場合にのみ機能します。前の答えを補足するために、要素がユーザー定義型であるセットを実装する方法を次に示します。
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))}
}