Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 围棋中的洗牌阵法_Arrays_Go - Fatal编程技术网

Arrays 围棋中的洗牌阵法

Arrays 围棋中的洗牌阵法,arrays,go,Arrays,Go,我试图翻译下面的Python代码 import random list = [i for i in range(1, 25)] random.shuffle(list) print(list) 但我发现我的Go版本冗长而笨拙,因为没有shuffle函数,我必须实现接口和转换类型 什么是我的代码的惯用Go版本?由于您的列表只是1到25之间的整数,您可以使用: 请注意,使用rand.Perm给出的置换是洗牌任何数组的有效方法 dest := make([]int, len(src)) perm

我试图翻译下面的Python代码

import random

list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)
但我发现我的Go版本冗长而笨拙,因为没有shuffle函数,我必须实现接口和转换类型


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

由于您的列表只是1到25之间的整数,您可以使用:

请注意,使用
rand.Perm
给出的置换是洗牌任何数组的有效方法

dest := make([]int, len(src))
perm := rand.Perm(len(src))
for i, v := range perm {
    dest[v] = src[i]
}
这是完全合理的,但也可以在不分配任何额外切片的情况下进行洗牌

for i := range slice {
    j := rand.Intn(i + 1)
    slice[i], slice[j] = slice[j], slice[i]
}
有关该算法的更多详细信息,请参阅
rand.Perm
实际上也在内部使用此算法。

有一个小错误。如果我们从最低索引迭代到最高索引,以获得一致(伪)随机洗牌,根据,我们必须从区间
[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]
    }

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

当使用
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]
如果您想使用它,您可以在这里找到它。

非常不灵活,因为
[]接口{}
作为输入。这里是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]

另外,不要忘记,因为1.10GO包含一个官方功能

文件:

数学/随机:添加洗牌 Shuffle使用Fisher-Yates算法

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

因此,
BenchmarkPerm30ViaShuffle
比标杆Perm30快约30%, 尽管需要单独的初始化循环 以及使用函数调用交换元素

另见原文

首先,如:


不要忘了随机播种,否则您将始终得到相同的顺序。
例如
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)

也许您还可以使用以下功能:

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
库中使用

下面是一个例子:

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
库,因此需要对其进行种子设定。有关更多详细信息,请参阅。

此问题有一个shuffle()实现:。我认为这是本文中的“由内而外”版本,而您省略了
I!=j
检查?查看维基百科页面,这似乎是“现代算法”(第一个变体)“inside out”版本似乎将结果存储在新数组中,而不是在适当的位置执行洗牌。警告:不,这不是“inside out”或“modern”。我建议不要这样做。“inside out”算法与数组/片的副本一起工作,即操作两个数组/片:
a
(洗牌)。在这里,我们只有一个元素,它声称在适当的位置运行。它也不是“现代的”,因为“现代的”应该从切片的末尾迭代到开头(不包括第一个元素)。在这里,它从第一个元素迭代到结尾(包括两者)。无论是迭代方向还是生成
j
的方式都应该改变。@谢谢。我已经在答案中包含了此链接。不要忘了随机设置种子,否则您将始终获得相同的顺序。例如
rand.seed(time.Now().UnixNano())
@Shell谢谢。我在回答中加入了您的评论以提高可视性。我不确定自回答后Perm方法是否已更改,但它返回“整数[0,n]的伪随机排列”。在这种情况下,结果将是0到24的排列。@JayJay这就是数字递增的原因(另一个解决方案是将0更改为25)。继续向下滚动,1.10中现在支持这一点:如果答案有错误,则编辑错误答案,而不是编写另一个答案。
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)
}