web-dev-qa-db-ja.com

マップから任意のキー/アイテムを取得します

私はGoを初めて使い、マップから任意のアイテムを取得したいと思っています。それを行う慣用的な方法は何ですか?私はこのようなことしか考えられません:

func get_some_key(m map[int]int) int {
    for k := range m {
        return k
    }
    return 0
}

私がそれを望む理由は、一連のジョブを維持するためにマップを使用しており、マップを使用すると、保留中のジョブを取得したり、O(1)で完了したジョブを削除したりできるからです。これは一般的な要件であると思いますが、Goでそれを行う方法は明らかではありません。

35
chuchao333

ハッシュテーブルから任意のキーを取得することが一般的な要件であるかどうかについて説明します。多くの場合、他の言語マップの実装にはこの機能がありません(例: C#の辞書

ただし、ソリューションはおそらく最速のものですが、制御されない擬似ランダムアルゴリズムが残されます。また、現在の実装では擬似ランダムアルゴリズムを使用していますが、 Go Specification は実際にランダムであることを保証するものではなく、予測可能であることを保証するものではありません。

マップの反復順序は指定されておらず、反復ごとに同じになる保証はありません。

ランダム化をさらに制御したい場合は、選択したランダム化を使用して、マップに含まれる値(またはキー)の更新されたスライス(math/Randまたはcrypto/Randより極端な場合)、スライス内のランダムに選択されたインデックスに格納された値を取得します。

16
ANisus

マップからランダムなキーを取得するには、乱数として2番目のカウンターが必要です。

// choices = map[string]...

i := Rand.Intn(len(choices))
var k string
for k = range choices {
  if i == 0 {
    break
  }
  i--
}

fmt.Println(k, choices[k])

マップには任意のタイプの有効なキーを含めることができ、変更する必要があるのはvar k string 合わせる。これを関数としてバンドルできます:

func randIntMapKey(m map[int]string) int {
    i := Rand.Intn(len(m))
    for k := range m {
        if i == 0 {
            return k
        }
        i--
    }
    panic("never")
}
7
Xeoncross

以下はより一般的なバージョンですが、効率は低いかもしれません。

    keys := reflect.ValueOf(mapI).MapKeys()
    return keys[Rand.Intn(len(keys))].Interface()

https://play.golang.org/p/0uvpJ0Dig4e

5
Briank