Próbowałem przetłumaczyć następujący kod Pythona na Go
import random
list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)
ale okazało się, że moja wersja Go jest długa i niezręczna, ponieważ nie ma funkcji odtwarzania losowego i musiałem zaimplementować interfejsy i konwertować typy.
Jaka byłaby idiomatyczna wersja mojego kodu w Go?
Odpowiedzi:
Ponieważ twoja lista składa się tylko z liczb całkowitych od 1 do 25, możesz użyć Perm :
list := rand.Perm(25) for i, _ := range list { list[i]++ }
Zauważ, że użycie permutacji podanej przez
rand.Perm
jest skutecznym sposobem na tasowanie dowolnej tablicy.dest := make([]int, len(src)) perm := rand.Perm(len(src)) for i, v := range perm { dest[v] = src[i] }
źródło
Odpowiedź dystroy jest całkowicie rozsądna, ale możliwe jest również tasowanie bez przydzielania dodatkowych plasterków.
for i := range slice { j := rand.Intn(i + 1) slice[i], slice[j] = slice[j], slice[i] }
Więcej informacji na temat algorytmu można znaleźć w tym artykule w Wikipedii .
rand.Perm
w rzeczywistości używa tego algorytmu również wewnętrznie.źródło
i!=j
czeku?Od 1.10 Go zawiera oficjalną funkcję tasowania Fisher-Yates .
Dokumentacja:
pkg/math/rand/#Shuffle
Zobacz także oryginalny CL 51891
Po pierwsze, jak komentuje przez shelll :
Przykład:
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ódło
rand.Seed(time.Now().UnixNano())
.Odpowiedź Evana Shawa zawiera drobny błąd. Jeśli iterujemy przez wycinek od najniższego indeksu do najwyższego, aby uzyskać jednolite (pseudo) losowe tasowanie, zgodnie z tym samym artykułem , musimy wybrać losową liczbę całkowitą z przedziału,
[i,n)
a nie z[0,n+1)
.Ta implementacja zrobi to, czego potrzebujesz w przypadku większych danych wejściowych, ale w przypadku mniejszych wycinków wykona niejednorodne tasowanie.
Aby wykorzystać
rand.Intn()
, możemy zrobić:for i := len(slice) - 1; i > 0; i-- { j := rand.Intn(i + 1) slice[i], slice[j] = slice[j], slice[i] }
zgodnie z tym samym algorytmem z artykułu z Wikipedii.
źródło
Może możesz również użyć następującej funkcji:
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] } }
źródło
Korzystając z
math/rand
pakietu, nie zapomnij ustawić źródła// 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.
Napisałem więc
Shuffle
funkcję, która bierze to pod uwagę: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] } }
I aby z niego skorzystać:
source := rand.NewSource(time.Now().UnixNano()) array := []interface{}{"a", "b", "c"} Shuffle(array, source) // [c b a]
Jeśli chcesz go użyć, możesz go znaleźć tutaj https://github.com/shomali11/util
źródło
Podejście Raeda jest bardzo nieelastyczne ze względu
[]interface{}
na wkład. Oto wygodniejsza wersja dla 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) } }
Przykładowe użycie:
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]
Nie zapominaj też, że małe kopiowanie jest lepsze niż mała zależność
źródło
Użyj Shuffle () z
math/rand
biblioteki.Oto przykład:
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) }
Ponieważ pochodzi z
math/rand
biblioteki, należy go obsiać. Więcej informacji znajdziesz tutaj .źródło