Go中的shuffle数组

时间:2012-09-04 13:42:28

标签: arrays go

我尝试将以下Python代码翻译为Go

import random

list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)

但发现我的Go版本冗长而笨拙,因为没有shuffle函数,我必须实现接口和转换类型。

我的代码的惯用Go版本是什么?

8 个答案:

答案 0 :(得分:98)

dystroy's answer是完全合理的,但也可以在不分配任何额外切片的情况下进行随机播放。

for i := range slice {
    j := rand.Intn(i + 1)
    slice[i], slice[j] = slice[j], slice[i]
}

有关算法的详细信息,请参阅this Wikipedia articlerand.Perm实际上也在内部使用此算法。

答案 1 :(得分:90)

由于您的列表只是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]
}

答案 2 :(得分:27)

Go 1.10可能包含官方Fisher-Yates shuffle功能。

请参阅CL 51891

  

math / rand:添加Shuffle

     

Shuffle使用Fisher-Yates算法。

     

由于这是新API,它为我们提供了机会   使用更快的Int31n实现,主要是避免划分。

     

结果,BenchmarkPerm30ViaShuffle是   比BenchmarkPerm30快约30%,   尽管需要单独的初始化循环   并使用函数调用来交换元素。

文档:pkg/math/rand/#Shuffle

示例:

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)

答案 3 :(得分:6)

Answer by Evan Shaw有一个小错误。如果我们迭代从最低索引到最高索引的切片,以获得统一(伪)随机混洗,根据same article,我们必须从区间<div class="wrapper"> <table id="zero-table"> <tr id="zero-row"> <td id="zero-data">0</td> </tr> </table> <table id="table-12"> <tr id="row-1"> <td class="data-1234">1</td> </tr> <tr id="row-2"> <td class="data-1234">2</td> </tr> </table> <table id="table-34"> <tr id="row-3"> <td class="data-1234">3</td> </tr> <tr id="row-4"> <td class="data-1234">4</td> </tr> </table> </div> 中选择一个随机整数,而不是[i,n)

该实现将执行您需要的更大输入,但对于较小的切片,它将执行非均匀的随机播放。

要使用[0,n+1),我们可以:

rand.Intn()

遵循维基百科文章中的相同算法。

答案 4 :(得分:2)

也许你也可以使用以下功能:

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]
   }
}

答案 5 :(得分: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

找到它

答案 6 :(得分:1)

由于输入[]interface{}

Raed's approach非常不灵活。这是 go&gt; = 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]

而且,不要忘记a little copying is better than a little dependency

答案 7 :(得分:0)

使用math/rand库中的Shuffle()

这是一个例子:

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库,因此需要播种。有关更多详细信息,请参见here