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实现,大多避免了分割。

因此, BenchmarkPerm30ViaShuffleBenchmarkPerm30快大约30%,尽pipe需要一个单独的初始化循环并使用函数调用来交换元素。