虽然 shuffle 方法有效,但还有另一种方法不需要修改原始数组。事实上,您甚至不需要知道总共有多少项。您可以从流中随机选择 M 个项目,而您唯一需要保存的数据是这些 M 个项目的数组。
基本思想是从未知长度的流中挑选单个项目的算法的扩展。同样,您不知道流中有多少项目。所以你总是有一个选定的项目,但你可以随时更改选定的项目。
您从没有选定项目开始,计数为 0。当第一个项目进入时,您增加计数。然后你在 0 到 count-1 范围内选择一个随机数。如果值为 0,则使当前项成为选定项。选择的第一个随机数必须为 0,因为您的范围是 0 到 0。
当你阅读每个项目时,你增加计数,选择随机数,如果选择的随机数为 0,则将当前项目设为选中项目。它看起来像这样:
selected_item = none
count = 0
for each item
count = count + 1
if (random(count) == 0)
selected_item = current_item
这很有效,因为选择当前项目的机会随着每个项目的阅读而降低。也就是说,第一个项目以 1/1 的概率被选中。当第二个项目进来时,您有 1/2 的机会选择它来替换第一个项目。当您收到第三个项目时,您有 1/3 的机会将当前选择的项目替换为新项目。
当您到达流的末尾时,您将给予每个项目均等的被选中机会。
您可以很容易地将其扩展到多个项目。您首先选择进来的前 M 个项目,然后将它们放入您选择的项目数组中。然后,每当有新项目进入时,您会选择一个介于 0 和 count-1 之间的随机数,如果该数字小于 M,那么您将随机用新项目替换所选项目之一。它看起来像这样:
selected_items = array of M items
count = 0
for each item
if (count < M)
selected_items[count] = current_item
else
if (random(count) < M)
// pick a random number from 0 to M-1
// and replace that item with the new item
ix = random(M)
selected_items[ix] = current_item
我在我的博客Random selection 中写了更多详细信息。