次のPythonコードをGoに翻訳しようとしました
import random
list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)
しかし、シャッフル関数がなく、インターフェイスを実装して型を変換する必要があったため、Goバージョンは長くて扱いにくいことがわかりました。
私のコードの慣用的なGoバージョンは何でしょうか?
回答:
リストは1から25までの整数であるため、Permを使用できます。
list := rand.Perm(25)
for i, _ := range list {
list[i]++
}
によって与えられた順列を使用することrand.Perm
は、任意の配列をシャッフルするための効果的な方法であることに注意してください。
dest := make([]int, len(src))
perm := rand.Perm(len(src))
for i, v := range perm {
dest[v] = src[i]
}
dystroyの答えは完全に合理的ですが、追加のスライスを割り当てずにシャッフルすることも可能です。
for i := range slice {
j := rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
参照してください。このWikipediaの記事アルゴリズムの詳細については、を。rand.Perm
実際には、このアルゴリズムも内部で使用しています。
i!=j
チェックを省略しますか?
1.10以降、Goには公式のFisher-Yatesシャッフル機能が含まれています。
ドキュメンテーション: pkg/math/rand/#Shuffle
数学/ランド:シャッフルを追加
シャッフルはフィッシャー-イェーツアルゴリズムを使用します。
これは新しいAPIであるため、
Int31n
分割をほとんど回避するはるかに高速な実装を使用する機会が得られます。その結果、個別の初期化ループが必要であり、関数呼び出しを使用して要素を交換しているにもかかわらず、
BenchmarkPerm30ViaShuffle
はBenchmarkPerm30
、よりも約30%高速です。
オリジナルのCL51891も参照してください
ランダムにシードすることを忘れないでください。そうしないと、常に同じ順序になります。
例えばrand.Seed(time.Now().UnixNano()
例:
words := strings.Fields("ink runs from the corners of my mouth")
rand.Shuffle(len(words), func(i, j int) {
words[i], words[j] = words[j], words[i]
})
fmt.Println(words)
rand.Seed(time.Now().UnixNano())
。
EvanShawによる回答には小さなバグがあります。最低インデックスから最高にスライスを通じて我々反復を均一に(擬似)ランダムシャッフルを取得する場合は、によると、同じ記事で、我々は間隔からランダムな整数を選択する必要があります[i,n)
とは反対に[0,n+1)
。
この実装は、より大きな入力に必要なことを実行しますが、より小さなスライスの場合、不均一なシャッフルを実行します。
利用するにはrand.Intn()
、次のことができます。
for i := len(slice) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
ウィキペディアの記事と同じアルゴリズムに従います。
次の関数を使用することもできます。
func main() {
slice := []int{10, 12, 14, 16, 18, 20}
Shuffle(slice)
fmt.Println(slice)
}
func Shuffle(slice []int) {
r := rand.New(rand.NewSource(time.Now().Unix()))
for n := len(slice); n > 0; n-- {
randIndex := r.Intn(n)
slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1]
}
}
math/rand
パッケージを使用するときは、ソースを設定することを忘れないでください
// Random numbers are generated by a Source. Top-level functions, such as
// Float64 and Int, use a default shared Source that produces a deterministic
// sequence of values each time a program is run. Use the Seed function to
// initialize the default Source if different behavior is required for each run.
そこで、Shuffle
これを考慮した関数を作成しました。
import (
"math/rand"
)
func Shuffle(array []interface{}, source rand.Source) {
random := rand.New(source)
for i := len(array) - 1; i > 0; i-- {
j := random.Intn(i + 1)
array[i], array[j] = array[j], array[i]
}
}
そしてそれを使用するには:
source := rand.NewSource(time.Now().UnixNano())
array := []interface{}{"a", "b", "c"}
Shuffle(array, source) // [c b a]
使用したい場合は、https://github.com/shomali11/utilで見つけることができます。
Raedのアプローチは[]interface{}
、入力として非常に柔軟性がありません。go> = 1.8のより便利なバージョンは次のとおりです。
func Shuffle(slice interface{}) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
for i := length - 1; i > 0; i-- {
j := rand.Intn(i + 1)
swap(i, j)
}
}
使用例:
rand.Seed(time.Now().UnixNano()) // do it once during app initialization
s := []int{1, 2, 3, 4, 5}
Shuffle(s)
fmt.Println(s) // Example output: [4 3 2 1 5]
また、少しのコピーは少しの依存関係よりも優れていることを忘れないでください
ライブラリのShuffle()を使用しmath/rand
ます。
次に例を示します。
package main
import (
"fmt"
"math/rand"
"strings"
)
func main() {
words := strings.Fields("ink runs from the corners of my mouth")
rand.Shuffle(len(words), func(i, j int) {
words[i], words[j] = words[j], words[i]
})
fmt.Println(words)
}
それはから来ているので、math/rand
ライブラリーには、播種する必要があります。詳細については、こちらをご覧ください。