Golangでデータ構造を設定します


69

私は本当にGoogle golangが好きですが、実装者が標準ライブラリのセットなどの基本的なデータ構造を省略した理由は何ですか?


8
言語は実際にはgolangではなくGoと呼ばれます
-jozefg

92
しかし、「ゴラン」はより検索可能です
マット

18
もっと検索可能。グーグルの「go set」は、黒と白の破片で木の板の画像を返します。
ダグリチャードソン14

回答:


68

この省略の潜在的な理由の1つは、マップを使用してセットをモデル化するのが本当に簡単だということです。

正直に言うと、ちょっと見落としていると思いますが、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
以下は、ContainsメソッドとSizeメソッドを使用したわずかに改訂されたバージョンです。play.golang.org
Rick-777

19
代わりにmap[int]bool使用できますmap[int]struct{}。最後のほうが好きです。
pepper_chico

20
map[int]struct{}.. struct{}は0バイトかかります。
ブーパティラジャ

2
github.com/fatih/setは、マップと空の構造に基づいた私の実装です。スレッドセーフであり、シンプルなAPIを備えています。
ファティアルスラーン14年

6
map[int]struct{}あなたはif mymap["key"] {メンバーシップをチェックすることはできません。Googleの使用をお勧めしますbool(「セットを実装できます」の検索)。
-Timmmm

3

これはgolang単純さに焦点を当てていることに関係していると思います。set本当に便利になるsはdifferenceintersectionunionissubset、など..方法。おそらくgolangチームは、1つのデータ構造には多すぎると感じました。しかし、そうでない場合にのみ持っている「ダムセット」addcontainsそしてremove簡単に複製することができるmap@jozefgで説明したように。


同意しません。セットは、主にメンバーシップチェックと一意性セマンティクスに使用されます。これらのメソッドがなくても、セット実装は完全に使用可能です。そうは言っても、実装するのは簡単です。
セダットカパノグル

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メソッドはである必要がありp1 == p2ます。
デイブC

1
構造体の等価性は明確に定義されていますが、構造体にマップまたはスライスがフィールドとして含まれている場合、値ではなく参照によって比較されます。これはあなたが望むものではないかもしれません。
チャイムレイブハルバート

1
メンバーの数に関係なく一定の時間がかかるContains一方、線形の時間がかかるため、このソリューションには少し問題がありaMap[]ます。より良い解決策は、各メンバーのコンテンツに基づいて一意のキーを内部的に作成し、map型が提供する一定時間のクエリを活用することです。キャッシュの動作などを考慮するより高速なソリューションも存在します。
チャイムレイブハルバート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.