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

huangapple go评论76阅读模式
英文:

How to pick a random number every time from a list

问题

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

以下是更清晰的Python代码示例。

我有这个列表:

listbytes = [87, 88, 89, 90]

还有这个函数用于拆分数据:

def chunks(lst, n):
    "从lst中生成连续的块,其中n是可能的大小列表"
    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的随机值,所以:
一个块的大小可能是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的随机值。

期望的输出是相同的:每次块的大小都应该是随机的。

如何在Go中实现相同的目标呢?

英文:

The goal: pick a random number from a list every time a chunk is generated

Python code example to make it more clear.

I have this list:

listbytes = [87, 88, 89, 90]

And this function which splits the data:

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

And I call it this way:

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

Every chunk created has a random size from 87 to 90, so:
1 chunk may have the size of 87, the next one may have the size of 90, and so on..

I have a similar function in Go which splits the data:

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

The difference between this and the one in python is that the data is chunked using a fixed number. Example:

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

This will chunk the data with a fixed size of 100, so every chunk has a size of 100, while with python is a random size from 87 to 90.

The desired output is the same thing: the chunks should have a random size everytime.

How can I achieve the same goal but in go?

答案1

得分: 2

我认为这是你的Python程序的Go版本(加上了一点点的main函数来运行它):

package main

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

// split函数将buf分割成一个由长度随机选择自sizes的切片组成的切片,
// 除了最后一个切片。最后一个切片的长度小于等于从sizes中选择的某个大小,
// 但可能大于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 := 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 Playground的链接,你可以在上面轻松查看和运行代码:
https://play.golang.org/p/U1vkPAKOQmI
(请注意,Go Playground上的时间始终相同,因此它始终运行相同的结果)。

英文:

I think this is the Go version of your Python program (with a little main to run it):

package main

import (
  &quot;fmt&quot;
  &quot;math/rand&quot;
  &quot;time&quot;
)

// split breaks buf into a slice of slices whose lengths
// are randomly chosen from sizes, except for the last slice.
// The last slice&#39;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) &gt; 0 {
        sz := sizes[r.Intn(len(sizes))]
        if sz &gt; len(buf) {
           sz = len(buf)
        } 
        chunk, buf = buf[:sz], buf[sz:]
        chunks = append(chunks, chunk)
    }
    return chunks
}

func main() {
    // Go&#39;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(&quot;result=%v\n&quot;, split(r, buf, sizes))
}

Here's a Go playground link for the same (so you can easily see and run):
https://play.golang.org/p/U1vkPAKOQmI
(Note that the time is always the same at the Go playground, so that it always runs the same).

答案2

得分: 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() {}
英文:

A solution on top of io.Reader

main_test.go

package main

import (
	&quot;bytes&quot;
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;math/rand&quot;
	&quot;strings&quot;
	&quot;time&quot;
)

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 &amp;&amp; len(r.buf) &lt; 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 &gt; 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=&quot;%s&quot;`+&quot;\n&quot;, n, err, out[:n])
	}
	// Output:
	// n=2 err=&lt;nil&gt; buf=&quot;12&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;34&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;51&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;2&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;3&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;45&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;1&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;23&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;4&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;51&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;2&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;34&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;5&quot;
}

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=&quot;%s&quot;`+&quot;\n&quot;, n, err, out[:n])
	}
	// Output:
	// n=2 err=&lt;nil&gt; buf=&quot;12&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;34&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;51&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;2&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;3&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;45&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;1&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;23&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;4&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;51&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;2&quot;
	// n=2 err=&lt;nil&gt; buf=&quot;34&quot;
	// n=0 err=&lt;nil&gt; buf=&quot;&quot;
	// n=1 err=&lt;nil&gt; buf=&quot;5&quot;
}

func main() {}

huangapple
  • 本文由 发表于 2021年7月27日 22:50:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/68547099.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定