0
0

More than 3 years have passed since last update.

sort.SearchStrings の注意点と対策コード

Posted at

記事の概要

文字列を二分探索する関数 sort.SearchStrings は、その返り値では、
探索対象の文字列が存在するか、存在しないかが判断できない。
その説明と対策コードを考え、書いた。

参考文献

https://golang.org/pkg/sort/#SearchStrings
https://golang.org/src/sort/search.go?s=3680:3724#L91

sort.SearchStrings の仕様

sort.SearchStrings は 公式ドキュメントによると、
昇順にソートされた文字列スライスと文字列xを受け取り、スライスの中にxがあるか二分探索する。
文字列スライスの中にxが存在する場合, そのインデックスを返し、
文字列スライスの中にxが存在しない場合、そのスライスに、昇順を維持して、xを挿入するためのインデックスを返す。

func SearchStrings(a []string, x string) int
SearchStrings searches for x in a sorted slice of strings and returns the index 
as specified by Search. The return value is the index to insert x if x is not 
present (it could be len(a)). The slice must be sorted in ascending order.

何を問題としているか

返り値から探索対象の文字列が存在するか、存在しないかが判断できない。
例えば、以下のコードでコメントは出力結果を表しているが、以下の結果が一致してしまっている

  • a を探索した場合: スライスに a がなく、a の挿入位置 0 が返る
  • b を探索した場合: スライスに b があり、その位置の 0 が返る
var slice = []string{"b"}

fmt.Println(sort.SearchStrings(slice, "a")) // 0
fmt.Println(sort.SearchStrings(slice, "b")) // 0
fmt.Println(sort.SearchStrings(slice, "c")) // 1

どうするのか

返ったインデックスを元に、スライスにアクセスし、その文字列と探索文字列が等しいか調べる。
ただし、公式ドキュメントの言及(it could be len(a))や、上の例の c の探索のように、
範囲外のインデックスが返る場合があるので、その場合を避けて考える。以下がそのコードである.

    var target = "b"
    var slice = []string{"b", "d"}
    var idx = sort.SearchStrings(slice, target)

    // 存在するかを調べる
    if idx != len(slice) && slice[idx] == target {
        fmt.Println("Exists")
    }

    // 存在しないことを調べる
    if idx == len(slice) || slice[idx] != target {
        fmt.Println("None")
    }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0