在 Go 中随机化 MongoDB 查询的顺序
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("request done")
if err5 != nil {
panic(err5)
}
var i = 0
for _,badvideo := range results {
}
我想随机化浏览查询项目的顺序,以便对请求的每个项目进行操作...
所以每次我 运行 它时,我都会以不同的顺序浏览它。
手动洗牌
这是一个简单的洗牌算法,它洗牌(随机化)一个 []BadVido
切片:
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()
函数随机 select 从切片中为每个索引添加一个元素。它就像向下遍历所有元素一样,并且 selects 来自剩余切片的随机元素(包括我们当前正在 selecting 的元素的索引,因为随机顺序还包括元素 "stays in place"),并使用随机索引将元素与所选的随机元素交换。循环一直持续到 i > 0
(而不是直到 i >=0
),因为如果只剩下 1 个元素,则不需要将其与自身交换。
使用rand.Perm()
shuffle()
的另一种变体可以利用 rand.Perm()
,其中 returns 包含随机数字的切片。我们可以使用这些随机数来告诉如何重新排序结果:
func shuffle(r []BadVideo) {
r2 := append([]BadVideo(nil), r...)
for i, j := range rand.Perm(len(r)) {
r[i] = r2[j]
}
}
在 Go Playground 上试试这个变体。
这里要注意一件事:在进行重新排序之前,我们必须保存原始切片(复制它),因此我们可以 select 在写入时随机索引指定的原始元素结果在切片中。我通过将完整切片附加到 nil
切片来创建副本。
这是我的查询:
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 {
}
我想随机化浏览查询项目的顺序,以便对请求的每个项目进行操作...
所以每次我 运行 它时,我都会以不同的顺序浏览它。
手动洗牌
这是一个简单的洗牌算法,它洗牌(随机化)一个 []BadVido
切片:
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()
函数随机 select 从切片中为每个索引添加一个元素。它就像向下遍历所有元素一样,并且 selects 来自剩余切片的随机元素(包括我们当前正在 selecting 的元素的索引,因为随机顺序还包括元素 "stays in place"),并使用随机索引将元素与所选的随机元素交换。循环一直持续到 i > 0
(而不是直到 i >=0
),因为如果只剩下 1 个元素,则不需要将其与自身交换。
使用rand.Perm()
shuffle()
的另一种变体可以利用 rand.Perm()
,其中 returns 包含随机数字的切片。我们可以使用这些随机数来告诉如何重新排序结果:
func shuffle(r []BadVideo) {
r2 := append([]BadVideo(nil), r...)
for i, j := range rand.Perm(len(r)) {
r[i] = r2[j]
}
}
在 Go Playground 上试试这个变体。
这里要注意一件事:在进行重新排序之前,我们必须保存原始切片(复制它),因此我们可以 select 在写入时随机索引指定的原始元素结果在切片中。我通过将完整切片附加到 nil
切片来创建副本。