J'ai essayé de traduire le code suivant Python to Go
import random
list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)
mais j'ai trouvé ma version Go longue et maladroite car il n'y a pas de fonction de lecture aléatoire et j'ai dû implémenter des interfaces et convertir des types.
Quelle serait une version Go idiomatique de mon code?
Comme votre liste n'est que les entiers de 1 à 25, vous pouvez utiliser Perm :
list := Rand.Perm(25)
for i, _ := range list {
list[i]++
}
Notez que l'utilisation d'une permutation donnée par Rand.Perm
est un moyen efficace de mélanger n'importe quel tableau.
dest := make([]int, len(src))
perm := Rand.Perm(len(src))
for i, v := range perm {
dest[v] = src[i]
}
réponse de dystroy est parfaitement raisonnable, mais il est également possible de mélanger sans allouer de tranches supplémentaires.
for i := range slice {
j := Rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
Voir cet article Wikipedia pour plus de détails sur l'algorithme. Rand.Perm
utilise également cet algorithme en interne.
Go 1.10 peut inclure une fonction officielle Fisher-Yates shuffle .
Voir CL 51891 :
math/Rand: ajouter Shuffle
Shuffle utilise l'algorithme Fisher-Yates.
Comme il s'agit d'une nouvelle API, elle nous offre la possibilité d'utiliser un _ beaucoup plus rapide
Int31n
implémentation qui évite surtout la division.Par conséquent,
BenchmarkPerm30ViaShuffle
est environ 30% plus rapide queBenchmarkPerm30
, malgré la nécessité d'une boucle d'initialisation distincte et l'utilisation d'appels de fonction pour permuter les éléments.
Documentation: pkg/math/Rand/#Shuffle
Exemple:
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)
Réponse d'Evan Shaw a un bug mineur. Si nous parcourons la tranche de l'indice le plus bas au plus élevé, pour obtenir un mélange aléatoire (pseudo) uniforme, selon le même article , nous devons choisir un entier aléatoire dans l'intervalle [i,n)
par opposition à [0,n+1)
.
Cette implémentation fera ce dont vous avez besoin pour des entrées plus grandes, mais pour des tranches plus petites, elle effectuera un shuffle non uniforme.
Pour utiliser Rand.Intn()
, nous pouvons faire:
for i := len(slice) - 1; i > 0; i-- {
j := Rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
en suivant le même algorithme de l'article Wikipedia.
Vous pouvez peut-être également utiliser la fonction suivante:
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]
}
}
approche de Raed est très rigide à cause de []interface{}
en entrée. Voici une version plus pratique pour 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)
}
}
Exemple d'utilisation:
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]
Et aussi, n'oubliez pas que ne petite copie vaut mieux qu'une petite dépendance
Lorsque vous utilisez le math/Rand
package, n'oubliez pas de définir une source
// 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.
J'ai donc écrit une fonction Shuffle
qui prend cela en considération:
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]
}
}
Et pour l'utiliser:
source := Rand.NewSource(time.Now().UnixNano())
array := []interface{}{"a", "b", "c"}
Shuffle(array, source) // [c b a]
Si vous souhaitez l'utiliser, vous pouvez le trouver ici https://github.com/shomali11/util
Utilisez Shuffle () dans le math/Rand
bibliothèque.
Voici un exemple:
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)
}
Puisqu'il vient du math/Rand
bibliothèque dont elle a besoin pour être initialisée. Voir ici pour plus de détails.