Go中的随机数组
我试图将下面的Python代码翻译成Go
import random list = [i for i in range(1, 25)] random.shuffle(list) print(list)
但发现我的Go版本冗长而尴尬,因为没有随机播放function,我不得不实现接口和转换types。
什么是我的代码惯用的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] }
看到这个维基百科文章关于algorithm的更多细节。 rand.Perm
内部使用这个algorithm。
通过回答Evan Shaw有一个小错误。 如果我们遍历从最低索引到最高索引的分片,为了得到一个统一的(伪)随机洗牌,根据同一篇文章 ,我们必须从区间[i,n)
select一个随机整数[i,n)
而不是[0,n+1)
。
这个实现将会做你所需要的更大的input,但对于更小的片,它将执行不均匀的混洗。
要使用rand.Intn()
,我们可以这样做:
for i := len(slice) - 1; i > 0; i-- { j := rand.Intn(i + 1) slice[i], slice[j] = slice[j], slice[i] }
遵循维基百科文章中的相同algorithm。
使用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) // [cba]
如果你想使用它,你可以在这里find它https://github.com/shomali11/util
由于[]interface{}
作为input, Raed的方法非常不灵活。 这里是更方便的版本去> = 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]
另外,不要忘记, 一点点复制比一点点依赖性更好
Go 1.10可能包含一个Fisher-Yates正式洗牌function。
见CL 51891 :
math/兰德:添加Shuffle
Shuffle使用Fisher-Yatesalgorithm。
由于这是一个新的API,它使我们有机会使用一个更快的
Int31n
实现,大多避免了分割。因此,
BenchmarkPerm30ViaShuffle
比BenchmarkPerm30
快大约30%,尽pipe需要一个单独的初始化循环并使用函数调用来交换元素。