202

Goでランダムな文字列を生成しようとしていますが、これまでに書いたコードは次のとおりです。

package main

import (
    "bytes"
    "fmt"
    "math/rand"
    "time"
)

func main() {
    fmt.Println(randomString(10))
}

func randomString(l int) string {
    var result bytes.Buffer
    var temp string
    for i := 0; i < l; {
        if string(randInt(65, 90)) != temp {
            temp = string(randInt(65, 90))
            result.WriteString(temp)
            i++
        }
    }
    return result.String()
}

func randInt(min int, max int) int {
    rand.Seed(time.Now().UTC().UnixNano())
    return min + rand.Intn(max-min)
}

私の実装は非常に遅いです。を使用してシードするtimeと、一定時間同じ乱数が発生するため、ループが何度も繰り返されます。コードを改善するにはどうすればよいですか?

4

10 に答える 10

275

同じシードを設定するたびに、同じシーケンスが得られます。もちろん、高速ループでシードを時間に設定している場合は、おそらく同じシードで何度も呼び出すことになります。

あなたの場合、randInt別の値になるまで関数を呼び出しているので、(Nano によって返される) 時間が変わるのを待っています。

すべての疑似乱数ライブラリと同様に、特定のシーケンスを特に再現する必要がない限り、たとえばプログラムを初期化するときなどに、シードを 1 回だけ設定する必要があります (これは通常、デバッグと単体テストのためにのみ行われます)。

その後Intn、次のランダムな整数を取得するために呼び出すだけです。

rand.Seed(time.Now().UTC().UnixNano())行を randInt 関数から main の先頭に移動すると、すべてが高速になります。そして、次の理由で.UTC()通話を失います。

UnixNano は、1970 年 1 月 1 日 UTC から経過したナノ秒数である Unix 時間として t を返します。

また、文字列の作成を簡素化できると思うことにも注意してください。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    fmt.Println(randomString(10))
}

func randomString(l int) string {
    bytes := make([]byte, l)
    for i := 0; i < l; i++ {
        bytes[i] = byte(randInt(65, 90))
    }
    return string(bytes)
}

func randInt(min int, max int) int {
    return min + rand.Intn(max-min)
}
于 2012-09-07T15:33:05.050 に答える
18

後世のためにそれを捨てるだけです。初期の文字セット文字列を使用してランダムな文字列を生成することが望ましい場合があります。これは、文字列が人間によって手動で入力されることになっている場合に便利です。0、O、1、および l を除外すると、ユーザー エラーを減らすことができます。

var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"

// generates a random string of fixed size
func srand(size int) string {
    buf := make([]byte, size)
    for i := 0; i < size; i++ {
        buf[i] = alpha[rand.Intn(len(alpha))]
    }
    return string(buf)
}

通常、init()ブロック内にシードを設定します。それらはここに文書化されています: http://golang.org/doc/effective_go.html#init

于 2012-09-07T17:09:31.983 に答える
14

OK、なぜそんなに複雑なのか!

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed( time.Now().UnixNano())
    var bytes int

    for i:= 0 ; i < 10 ; i++{ 
        bytes = rand.Intn(6)+1
        fmt.Println(bytes)
        }
    //fmt.Println(time.Now().UnixNano())
}

これは dystroy のコードに基づいていますが、私のニーズには合っています。

It's die six (rands ints 1 =< i =< 6)

func randomInt (min int , max int  ) int {
    var bytes int
    bytes = min + rand.Intn(max)
    return int(bytes)
}

上記の機能はまったく同じものです。

この情報がお役に立てば幸いです。

于 2012-10-20T11:23:27.020 に答える
1

以下のプログラムを試してみたところ、毎回異なる文字列が表示されました

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func RandomString(count int){
  rand.Seed(time.Now().UTC().UnixNano()) 
  for(count > 0 ){
    x := Random(65,91)
    fmt.Printf("%c",x)
    count--;
  }
}

func Random(min, max int) (int){
 return min+rand.Intn(max-min) 
}

func main() {
 RandomString(12)
}

そして、私のコンソールの出力は

D:\james\work\gox>go run rand.go
JFBYKAPEBCRC
D:\james\work\gox>go run rand.go
VDUEBIIDFQIB
D:\james\work\gox>go run rand.go
VJYDQPVGRPXM
于 2020-08-08T02:19:20.073 に答える
0

ナノ秒です。同じシードを 2 回取得する可能性はどれくらいですか。
とにかく、助けてくれてありがとう、これがすべての入力に基づく私の最終的な解決策です。

package main

import (
    "math/rand"
    "time"
)

func init() {
    rand.Seed(time.Now().UTC().UnixNano())
}

// generates a random string
func srand(min, max int, readable bool) string {

    var length int
    var char string

    if min < max {
        length = min + rand.Intn(max-min)
    } else {
        length = min
    }

    if readable == false {
        char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    } else {
        char = "ABCDEFHJLMNQRTUVWXYZabcefghijkmnopqrtuvwxyz23479"
    }

    buf := make([]byte, length)
    for i := 0; i < length; i++ {
        buf[i] = char[rand.Intn(len(char)-1)]
    }
    return string(buf)
}

// For testing only
func main() {
    println(srand(5, 5, true))
    println(srand(5, 5, true))
    println(srand(5, 5, true))
    println(srand(5, 5, false))
    println(srand(5, 7, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 4, true))
    println(srand(5, 400, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
}
于 2012-09-11T09:53:43.063 に答える