Golang 如何获得整数的随机换位
在Golang中生成随机数是一种常见的需求。但是如何生成随机数,并不止一个方法。有些程序员可能会用时间戳作为seed来生成随机数,有些人可能会用crypto/rand包提供的随机数生成器,这些方法都是可行的,但是如果我们想要生成整数的随机换位,这些方法并不好用。下面我们就来介绍几种实现整数随机换位的方法。
方法一
第一种方法比较简单,就是先将整数转换成字符串,再随机打乱字符串中的字符,最后将字符串转换回整数。这个方式比较容易理解,但是有一个缺点,如果需要处理非常大的整数,这个方法会比较慢。
import (
"fmt"
"strconv"
"math/rand"
"time"
)
func ShuffleInt(n int) int {
strn := strconv.Itoa(n)
r := []rune(strn)
rand.Seed(time.Now().UnixNano())
// 这里使用了 Fisher–Yates shuffle 算法
for i := len(r) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
r[i], r[j] = r[j], r[i]
}
str := string(r)
m, _ := strconv.Atoi(str)
return m
}
func main() {
n := 123456
m := ShuffleInt(n)
fmt.Println(m) // 可能输出的结果是 341526 或 321546 等等
}
方法二
第二种方法是通过随机交换整数的两个数字来实现的。这个方式比方法一更加高效,因为它不需要将整数转换成字符串再进行操作。而是直接对整数的每一位进行交换。但是需要注意的是,这个方法不能处理有0存在的数字。
import (
"fmt"
"math/rand"
"time"
)
func SwapInt(n int) int {
a := []int{}
for n > 0 {
a = append(a, n%10)
n /= 10
}
rand.Seed(time.Now().UnixNano())
for i := len(a) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
a[i], a[j] = a[j], a[i]
}
m := 0
for i := len(a) - 1; i >= 0; i-- {
m = m*10 + a[i]
}
return m
}
func main() {
n := 123456
m := SwapInt(n)
fmt.Println(m) // 可能输出的结果是 245316 或者 346521 等等
}
方法三
第三种方法使用的是math/rand包中的perm函数,它可以生成指定长度的随机排列。我们可以先将整数转换成字符串,再将字符串转换成rune类型的数组,然后对这个数组进行随机排列,最后将排列后的数组转换回字符串,再将字符串转换成整数。看起来比方法一和方法二都要简单。
import (
"fmt"
"strconv"
"math/rand"
"time"
)
func RandPermutation(n int) int {
strn := strconv.Itoa(n)
r := []rune(strn)
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(r), func(i, j int) {
r[i], r[j] = r[j], r[i]
})
str := string(r)
m, _ := strconv.Atoi(str)
return m
}
func main() {
n := 123456
m := RandPermutation(n)
fmt.Println(m) // 可能输出的结果是 341526 或 654321 等等
}
结论
在Golang中生成随机数有多种方法,但是如果需要实现整数的随机换位,以上三种方法都是可行的。方法一比较容易理解,可以处理任何大小的数字,但是对于大数字的处理效率较低。方法二效率比方法一高,但是无法处理有0存在的数字。方法三使用的是math/rand包中的perm函数,看起来最简单,但是可能并不高效。因此根据实际情况选择合适的方法是很重要的。