गो में फेरबदल सरणी


82

मैंने निम्नलिखित पायथन कोड को गो में अनुवाद करने का प्रयास किया

import random

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

लेकिन मेरे गो संस्करण को लंबा और अजीब पाया क्योंकि कोई फेरबदल कार्य नहीं है और मुझे इंटरफेस को लागू करना और प्रकारों को परिवर्तित करना था।

मेरे कोड का एक मुहावरेदार गो संस्करण क्या होगा?


2
इस प्रश्न में एक फेरबदल () कार्यान्वयन है: गो में अर्रे का उपचार
जोएर्ड

जवाबों:


96

जैसा कि आपकी सूची केवल 1 से 25 तक पूर्णांक है, आप पर्म का उपयोग कर सकते हैं :

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

यदि मैं इस उत्तर के बाद से पर्म विधि बदल गया हूँ, तो मैं अनिश्चित हूँ, लेकिन यह "पूर्णांक का एक छद्म यादृच्छिक क्रमांकन [0, n)" लौटाता है। इस परिदृश्य में, परिणाम 0 से 24 के क्रमपरिवर्तन होगा।
जयजय

1
@JayJay इसीलिए संख्या में वृद्धि हुई है (दूसरा समाधान सिर्फ 0 से 25 को बदलने के लिए किया गया होगा)।
डेसीस सेग्यूरेट

1
नीचे स्क्रॉल करते रहें, यह अब 1.10: stackoverflow.com/a/46185753/474189
डंकन जोन्स

101

dystroy का उत्तर पूरी तरह से उचित है, लेकिन किसी भी अतिरिक्त स्लाइस को आवंटित किए बिना फेरबदल करना भी संभव है।

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

देखें यह विकिपीडिया लेख एल्गोरिथ्म पर अधिक जानकारी के लिए। rand.Permवास्तव में आंतरिक रूप से भी इस एल्गोरिथ्म का उपयोग करता है।


4
मैं इसे लेता हूं यह लेख में "अंदर-बाहर" संस्करण है, और आप i!=jचेक को खत्म करते हैं ?
मैट जॉइनर

विकिपीडिया पृष्ठ को देखते हुए, यह "आधुनिक एल्गोरिथ्म" (पहला संस्करण) प्रतीत होता है। "इन-आउट" संस्करण परिणाम को फेरबदल करने के बजाय एक नए सरणी में संग्रहीत करता है।
जोचेन

49

चूंकि 1.10 गो में एक आधिकारिक फिशर-येट्स फेरबदल फ़ंक्शन शामिल है।

प्रलेखन: pkg/math/rand/#Shuffle

गणित / रैंड: शफ़ल जोड़ें

फेरबदल फिशर-येट्स एल्गोरिथ्म का उपयोग करता है।

चूंकि यह नया एपीआई है, यह हमें बहुत तेज Int31nकार्यान्वयन का उपयोग करने का अवसर देता है जो ज्यादातर विभाजन से बचा जाता है।

नतीजतन, एक अलग इनिशियलाइज़ेशन लूप की आवश्यकता के बावजूद BenchmarkPerm30ViaShuffleलगभग 30% तेज है BenchmarkPerm30और स्वैप तत्वों के लिए फ़ंक्शन कॉल का उपयोग करता है।

मूल सीएल 51891 भी देखें

सबसे पहले, जैसा कि शेल ने टिप्पणी की है :

यादृच्छिक को बीज देना मत भूलना, या आपको हमेशा एक ही आदेश मिलेगा।
उदाहरण के लिए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)

@Deleplace धन्यवाद। मैंने इस लिंक को उत्तर में शामिल किया है।
VonC

3
यादृच्छिक को बीज देना मत भूलना, या आपको हमेशा एक ही आदेश मिलेगा। उदाहरण के लिए rand.Seed(time.Now().UnixNano())
शंख

@shelll धन्यवाद। अधिक दृश्यता के जवाब में मैंने आपकी टिप्पणी को शामिल किया है।
वॉन

7

इवान शॉ के उत्तर में एक मामूली बग है। यदि हम एक ही लेख के अनुसार समान सूचकांक (छद्म) यादृच्छिक फेरबदल पाने के लिए सबसे कम सूचकांक से टुकड़ा के माध्यम से पुनरावृति करते हैं , तो हमें [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]
    }

विकिपीडिया लेख से समान एल्गोरिथ्म का पालन।


यदि एक उत्तर में बग है तो गलत उत्तर को संपादित करें, बजाय एक और उत्तर लिखने के।
याकूब मार्बल

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

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 पर देख सकते हैं


1

[]interface{}इनपुट की वजह से रीड का दृष्टिकोण बहुत ही अनम्य है । यहां गो> = 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

लाइब्रेरी से शफल () का उपयोग करें 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पुस्तकालय से आता है, इसलिए इसे वरीयता देने की आवश्यकता है। अधिक जानकारी के लिए यहां देखें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.