如何每次从列表中选择一个随机数

时间:2021-07-27 14:50:19

标签: go random chunks

目标:每次生成块时从列表中选择一个随机数

Python 代码示例使其更清晰。

我有这个清单:

listbytes = [87, 88, 89, 90]

还有这个分割数据的函数:

def chunks(lst, n):
"Yield successive chunks from lst, where n is a list of possible sizes"
    i = 0
    while i < len(lst):
        k = min(random.choice(n), len(lst) - i)
        yield lst[i:i + k]
        i += k

我这样称呼它:

for chunk in chunks(d, listbytes):
    ......

创建的每个块都有一个从 87 到 90 的随机大小,所以: 1 个块的大小可能为 87,下一个块的大小可能为 90,依此类推..

我在 Go 中有一个类似的函数来分割数据:

func split(buf []byte, lim int) [][]byte {
    var chunk []byte
    chunks := make([][]byte, 0, len(buf)/lim+1)
    for len(buf) >= lim {
        chunk, buf = buf[:lim], buf[lim:]
        chunks = append(chunks, chunk)
    }
    if len(buf) > 0 {
        chunks = append(chunks, buf[:len(buf)])
    }
    return chunks
}

这和python中的区别在于数据是使用固定数字分块的。示例:

for _, chunk := range split(buf[:n], 100) {
    .......

这会将数据分块固定大小为 100,因此每个块的大小为 100,而 Python 的大小为 87 到 90。

所需的输出是一样的:块每次都应该有一个随机大小。

我怎样才能实现相同的目标但在运行中?

2 个答案:

答案 0 :(得分:3)

我认为这是你的 Python 程序的 Go 版本(有一些 main 来运行它):

package main

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

// split breaks buf into a slice of slices whose lengths
// are randomly chosen from sizes, except for the last slice.
// The last slice's length is less than or equal to a size that 
// was chosen from sizes, but may be larger than some other size
// found in sizes.
func split(r *rand.Rand, buf []byte, sizes []int) [][]byte {
    var chunk []byte
    chunks := make([][]byte, 0)
    for len(buf) > 0 {
        sz := sizes[r.Intn(len(sizes))]
        if sz > len(buf) {
           sz = len(buf)
        } 
        chunk, buf = buf[:sz], buf[sz:]
        chunks = append(chunks, chunk)
    }
    return chunks
}

func main() {
    // Go's RNG is deterministic unless seeded with current time.
    s := int64(time.Now().Nanosecond())
    r := rand.New(rand.NewSource(s))

    sizes := []int{2,3,5,7}
    buf := []byte{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25}

    fmt.Printf("result=%v\n", split(r, buf, sizes))
}

这是相同的 Go 游乐场链接(因此您可以轻松查看和运行): https://play.golang.org/p/U1vkPAKOQmI (请注意,Go Playground 的时间总是相同的,因此它始终运行相同)。

答案 1 :(得分:2)

基于 io.Reader 的解决方案

main_test.go

package main

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

type rndReader struct {
    R       io.Reader
    Rnd     interface{ Intn(n int) int }
    buf     []byte
    lastErr error
}

func (r *rndReader) Read(p []byte) (n int, err error) {
    if r.Rnd == nil {
        r.Rnd = rand.New(rand.NewSource(time.Now().Unix()))
    }
    if r.lastErr != nil && len(r.buf) < 1 {
        return 0, r.lastErr
    }
    // rather than a function argument (n), take len(p)
    j := len(p)
    if r.lastErr == nil {
        n, err = r.R.Read(p)            // read to p
        r.buf = append(r.buf, p[:n]...) // save the read
        r.lastErr = err
    }
    p = p[:0]                           // reset p, prepare it to receive the random chunk
    k := min(r.Rnd.Intn(j), len(r.buf)) // select a random k
    p = append(p, r.buf[:k]...)         // copy the desired portion from the internal buf to p
    copy(r.buf, r.buf[k:])              // re arrange the internal buffer
    r.buf = r.buf[:len(r.buf)-k]        // adjust its len.
    return len(p), nil
}

func min(n, k int) int {
    if n > k {
        return k
    }
    return n
}

func ExampleFromStrings() {
    in := strings.Repeat(`12345`, 4)
    s := strings.NewReader(in)

    r := rndReader{R: s, Rnd: rand.New(rand.NewSource(1))}
    out := make([]byte, 3)
    for {
        n, err := r.Read(out)
        if err != nil {
            break
        }
        fmt.Printf(`n=%v err=%v buf="%s"`+"\n", n, err, out[:n])
    }
    // Output:
    // n=2 err=<nil> buf="12"
    // n=0 err=<nil> buf=""
    // n=2 err=<nil> buf="34"
    // n=2 err=<nil> buf="51"
    // n=1 err=<nil> buf="2"
    // n=0 err=<nil> buf=""
    // n=1 err=<nil> buf="3"
    // n=2 err=<nil> buf="45"
    // n=1 err=<nil> buf="1"
    // n=0 err=<nil> buf=""
    // n=2 err=<nil> buf="23"
    // n=1 err=<nil> buf="4"
    // n=0 err=<nil> buf=""
    // n=2 err=<nil> buf="51"
    // n=1 err=<nil> buf="2"
    // n=2 err=<nil> buf="34"
    // n=0 err=<nil> buf=""
    // n=1 err=<nil> buf="5"
}

func ExampleFromBytes() {
    in := []byte(strings.Repeat(`12345`, 4))
    s := bytes.NewBuffer(in)

    r := rndReader{R: s, Rnd: rand.New(rand.NewSource(1))}
    out := make([]byte, 3)
    for {
        n, err := r.Read(out)
        if err != nil {
            break
        }
        fmt.Printf(`n=%v err=%v buf="%s"`+"\n", n, err, out[:n])
    }
    // Output:
    // n=2 err=<nil> buf="12"
    // n=0 err=<nil> buf=""
    // n=2 err=<nil> buf="34"
    // n=2 err=<nil> buf="51"
    // n=1 err=<nil> buf="2"
    // n=0 err=<nil> buf=""
    // n=1 err=<nil> buf="3"
    // n=2 err=<nil> buf="45"
    // n=1 err=<nil> buf="1"
    // n=0 err=<nil> buf=""
    // n=2 err=<nil> buf="23"
    // n=1 err=<nil> buf="4"
    // n=0 err=<nil> buf=""
    // n=2 err=<nil> buf="51"
    // n=1 err=<nil> buf="2"
    // n=2 err=<nil> buf="34"
    // n=0 err=<nil> buf=""
    // n=1 err=<nil> buf="5"
}

func main() {}