我知道类似的问题出现了很多,而且可能没有明确的答案,但我想从一个可能无限的数字子集中生成五个唯一的随机数(可能是0-20或0-1,000,000)。 />
唯一的问题是我不想运行while
循环或填充数组。
我目前的方法是简单地从子集中减去最后五个数字生成五个随机数。如果任何数字彼此匹配,则它们将在子集的末尾到达它们各自的位置。因此,如果第四个数字与任何其他数字匹配,它将下注设置为最后一个数字的第4个。
有没有人有一个“足够随机”的方法,并且不涉及昂贵的循环或数组?
请记住这是一种好奇心,而不是一些关键任务问题。如果每个人都没有发帖“你为什么会遇到这个问题?”我将不胜感激。答案。我只是在寻找想法 非常感谢!
答案 0 :(得分:8)
一个随机号码就足够了。
如果要在1-n范围内选择5个唯一数字的子集,则在1到(n选择r)中选择一个随机数。
保持从1到(n选择r)的1-1映射到可能的5个元素子集的集合,您就完成了。此映射是标准的,可以在Web上找到,例如:http://msdn.microsoft.com/en-us/library/aa289166%28VS.71%29.aspx
举个例子:
考虑从五个数字生成两个数字的子集的问题:
{1,...,5}的可能的2个元素子集是
1. {1,2}
2. {1,3}
3. {1,4}
4. {1,5}
5. {2,3}
6. {2,4}
7. {2,5}
8. {3,4}
9. {3,5}
10. {4,5}
现在5选2是10。
所以我们从1到10中选择一个随机数。假设我们得到8.现在我们在上面的序列中生成第8个元素:得到{3,4},所以你想要的两个数字是3和4。 / p>
我链接到的msdn页面显示了一个生成集合的方法,给定了数字。即给定8,它返回集合{3,4}。
答案 1 :(得分:4)
您最好的选择是循环,如:
$max = 20;
$numels = 5;
$vals = array();
while (count($vals) < $numels) {
$cur = rand(0, $max);
if (!in_array($cur, $vals))
$vals[] = $cur;
}
对于小范围,您可以使用array_rand
:
$max = 20;
$numels = 5;
$range = range(0, $max);
$vals = array_rand($range, $numels);
您还可以生成介于0和最大值之间的数字,另一个介于0和最大值1之间,...介于0和最大值4之间。然后你将x加到第n个生成的数字,其中x是以这种方式计算的数字:
映射是这样的:
1 2 3 4 5 6 7 8 9 (take 4) 1 2 3 4 5 6 7 8 9 (gives 4) 1 2 3 4 5 6 7 8 (take 5) 1 2 3 5 6 7 8 9 (gives 6) 1 2 3 4 5 6 7 (take 6) 1 2 3 5 7 8 9 (gives 8) 1 2 3 4 5 6 (take 5) 1 2 3 5 7 9 (gives 7) example, last extraction: x = 5 x >= 4? x == 6 x >= 6? x == 7 x >= 8? x == 7
答案 2 :(得分:2)
这个问题的一般形式非常有趣。是应该从元素池中选择(并从池中删除它们)还是应该在“点击”已经被捕获的元素时进行循环?
据我所知,random.sample 的python库实现在两种方法之间选择运行时,具体取决于输入列表大小的比例和要选择的元素数量
来自源代码的评论:
# When the number of selections is small compared to the
# population, then tracking selections is efficient, requiring
# only a small set and an occasional reselection. For
# a larger number of selections, the pool tracking method is
# preferred since the list takes less space than the
# set and it doesn't suffer from frequent reselections.
在OP提到的特定情况下(选择5个数字),我认为循环“在点击被采用的数字时”是可以的,除非伪随机生成器被破坏。
答案 3 :(得分:0)
因为你只是在寻找不同的想法:
呼叫Random.org以生成您需要的一组随机数。
答案 4 :(得分:0)
如果您知道大小N,则保持每个数字的概率为5 / N,生成0到1之间的随机数,如果小于5 / N,则保留该项目。当我们有5个项目时停止。
如果我们不知道N使用resorvoir sampling。
答案 5 :(得分:0)
Artefacto在C#上面的第二个解决方案的实现,作为ICollection上的帮助和扩展方法:
static class Program {
public static IEnumerable<int> Subset(int max) {
Random random = new Random();
List<int> selections = new List<int>();
for (int space = max; space > 0; space--) {
int selection = random.Next(space);
int offset = selections.TakeWhile((n, i) => n <= selection + i).Count();
selections.Insert(offset, selection + offset);
yield return selection + offset;
}
}
public static IEnumerable<T> Random<T>(this ICollection<T> collection) {
return Subset(collection.Count).Select(collection.ElementAt);
}
static void Main(string[] args) {
Subset(10000).Take(10).ToList().ForEach(Console.WriteLine);
"abcdefghijklmnopqrstuvwxyz".ToArray().Random().Take(5).ToList().ForEach(Console.WriteLine);
}
}