我试图将以下Python代码翻译为Go
import random
list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)
Run Code Online (Sandbox Code Playgroud)
但发现我的Go版本冗长而笨拙,因为没有shuffle函数,我必须实现接口和转换类型.
什么是我的代码的惯用Go版本?
Eva*_*haw 99
dystroy的答案是完全合理的,但也可以在不分配任何额外切片的情况下进行洗牌.
for i := range slice {
j := rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
Run Code Online (Sandbox Code Playgroud)
有关该算法的更多详细信息,请参阅此Wikipedia文章.rand.Perm实际上也在内部使用这个算法.
Den*_*ret 90
由于您的列表只是1到25之间的整数,您可以使用Perm:
list := rand.Perm(25)
for i, _ := range list {
list[i]++
}
Run Code Online (Sandbox Code Playgroud)
请注意,使用给定的排列rand.Perm是一种有效的方式来混洗任何数组.
dest := make([]int, len(src))
perm := rand.Perm(len(src))
for i, v := range perm {
dest[v] = src[i]
}
Run Code Online (Sandbox Code Playgroud)
Von*_*onC 32
Go 1.10可能包括官方的Fisher-Yates shuffle函数.
见CL 51891:
math/rand:添加Shuffle
Shuffle使用Fisher-Yates算法.
由于这是新的API,它使我们有机会使用更快的
Int31n实现,这主要避免了划分.因此,尽管需要单独的初始化循环并使用函数调用交换元素,但
BenchmarkPerm30ViaShuffle速度比快30%BenchmarkPerm30.
例:
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)
Run Code Online (Sandbox Code Playgroud)
小智 7
回答Evan Shaw有一个小错误.如果我们迭代从最低索引到最高索引的切片,以获得统一(伪)随机混洗,根据同一篇文章,我们必须从区间中选择一个随机整数[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]
}
Run Code Online (Sandbox Code Playgroud)
遵循维基百科文章中的相同算法.