web-dev-qa-db-ja.com

Goで文字列スライスに特定の値が含まれているかどうかを確認します

特定の値が文字列スライスにあるかどうかを確認する最良の方法は何ですか?他の言語でSetを使用しますが、GoにはSetがありません。

これまでのところ、私の最善の試みはこれです:

package main

import "fmt"

func main() {
    list := []string{"a", "b", "x"}
    fmt.Println(isValueInList("b", list))
    fmt.Println(isValueInList("z", list))
}

func isValueInList(value string, list []string) bool {
    for _, v := range list {
        if v == value {
            return true
        }
    }
    return false
}

http://play.golang.org/p/gkwMz5j09n

このソリューションは小さなスライスには問題ないはずですが、多くの要素を持つスライスにはどうすればよいでしょうか?

23
deamon

任意の順序で文字列のスライスがある場合、スライスに値が存在するかどうかを確認するには、O(n) time。これはすべての言語に適用されます。

何度も何度も検索する場合は、他のデータ構造を使用して検索を高速化できます。ただし、これらの構造の構築には少なくともO(n)時間が必要です。したがって、データ構造を複数回使用してルックアップを行う場合にのみメリットが得られます。

たとえば、文字列をマップにロードできます。ルックアップにはO(1)時間かかります。挿入にもO(1)初期ビルドの作成にかかる時間O(n)時間:

set := make(map[string]bool)
for _, v := range list {
    set[v] = true
}

fmt.Println(set["b"])

文字列スライスを並べ替えてから、バイナリ検索を実行することもできます。バイナリ検索はO(log(n))時間で発生します。構築にはO(n * log(n))時間かかります。

sort.Strings(list)
i := sort.SearchStrings(list, "b")
fmt.Println(i < len(list) && list[i] == "b")

理論上は無限の値が与えられていますが、マップは高速ですが、実際にはソートされたリストの検索が高速になる可能性が非常に高くなります。自分でベンチマークを行う必要があります。

47

セットを置き換えるには、map[string]struct{}を使用する必要があります。これは効率的で慣用的であると見なされ、「値」はまったくスペースを取りません。

セットを初期化します。

set := make(map[string]struct{})

アイテムを置く:

set["item"]=struct{}{}

アイテムが存在するかどうかを確認します。

_, isPresent := set["item"]

アイテムを削除します。

delete(set, "item")
8
Denys Séguret

マップを使用し、値を持つことができます。ブール

m := map[string] bool {"a":true, "b":true, "x":true}
if m["a"] { // will be false if "a" is not in the map
    //it was in the map
}

sort パッケージもあるので、スライスをソートしてバイナリ検索できます

3
nos