在Go中对MongoDB查询结果进行随机排序。

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

Randomize order of a MongoDB query in Go

问题

这是我的查询代码:

c := session.DB("searchV").C("video")
var results []BadVideo
err5 := c.Find(nil).All(&results)
fmt.Println("请求完成")
if err5 != nil {
    panic(err5)
}
var i = 0
for _, badvideo := range results {
}

我想要随机化浏览查询结果的顺序,以便对每个请求的项进行操作...

所以每次运行时,我以不同的顺序浏览它。

英文:

Here is my query :

c := session.DB("searchV").C("video")
var results []BadVideo
err5 := c.Find(nil).All(&results)
fmt.Println("request done")
if err5 != nil {
	panic(err5)
}
var i = 0
for _,badvideo := range results {
}

I would like to randomize the order of browsing the items of the query for making operation on each item of the request ...

So each time I run it, I browse it in a different order.

答案1

得分: 1

手动洗牌

这是一个简单的洗牌算法,用于对 []BadVideo 切片进行洗牌(随机化):

func shuffle(r []BadVideo) {
    for i := len(r) - 1; i > 0; i-- {
        j := rand.Intn(i + 1)
        r[i], r[j] = r[j], r[i]
    }
}

所以在加载结果后,只需对其调用 shuffle(results)

为了测试,我将使用一个简单的 BadVideo 类型:

type BadVideo struct {
    Name string
}

func main() {
    rand.Seed(time.Now().UnixNano())
    results := []BadVideo{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}
    shuffle(results)
    fmt.Println(results)
}

输出结果(在 Go Playground 上尝试):

[{c} {d} {b} {e} {a}]

工作原理:

为了对切片进行洗牌,shuffle() 函数会随机选择切片中的一个元素,并将其放置在每个索引位置上。它通过向下迭代所有元素,并从剩余的切片中随机选择一个元素(包括当前选择的元素的索引,因为随机顺序也包括元素“保持原位”的情况),然后使用随机索引将该元素与所选的随机元素交换位置。循环继续直到 i > 0(而不是 i >= 0),因为如果只剩下一个元素,就不需要将其与自身交换位置。

使用 rand.Perm()

shuffle() 的另一种变体可以利用 rand.Perm(),它返回一个包含随机排序数字的切片。我们可以使用这些随机数来指示如何重新排序结果:

func shuffle(r []BadVideo) {
    r2 := append([]BadVideo(nil), r...)
    for i, j := range rand.Perm(len(r)) {
        r[i] = r2[j]
    }
}

Go Playground 上尝试这个变体。

这里需要注意的一点是:在重新排序之前,我们必须保存原始切片(创建一个副本),以便在将结果写入切片时,可以根据随机索引选择原始元素。我通过将完整切片附加到 nil 切片来创建了一个副本。

英文:

Manual shuffling

Here's a simple shuffle algorithm, which shuffles (randomizes) a []BadVido slice:

func shuffle(r []BadVideo) {
	for i := len(r) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		r[i], r[j] = r[j], r[i]
	}
}

So after you loaded your results, simply call shuffle(results) on it.

For testing, I will use a simple BadVideo type:

type BadVideo struct {
	Name string
}

func main() {
	rand.Seed(time.Now().UnixNano())
	results := []BadVideo{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}
	shuffle(results)
	fmt.Println(results)
}

Output (try it on the Go Playground):

[{c} {d} {b} {e} {a}]

How it works:

To shuffle a slice, the shuffle() function randomly selects one element from the slice for each index. It does it like iterating over all elements downward, and selects a random element from the remaining slice (including index of the element we're currently selecting, because random orders also include ones where an element "stays in place"), and using a random index to swaps the element with the chosen random one. The loop goes until i > 0 (and not until i >=0), because if only 1 element left, no need to swap it with itself.

Using rand.Perm()

Another variant of shuffle() could take advantage of rand.Perm() which returns a slice containing shuffled numbers. We can use these random numbers to tell how to reorder the results:

func shuffle(r []BadVideo) {
	r2 := append([]BadVideo(nil), r...)
	for i, j := range rand.Perm(len(r)) {
		r[i] = r2[j]
	}
}

Try this variant on the Go Playground.

One thing to note here: before we do the reordering, we have to save the original slice (make a copy of it), so we can select the original elements specified by random indices when writing the results in the slice. I created a copy by appending the complete slice to a nil slice.

huangapple
  • 本文由 发表于 2017年4月1日 21:10:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/43157290.html
匿名

发表评论

匿名网友

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

确定