Python 的“random”模块有一个函数random.choice http://docs.python.org/library/random.html#random.choice
random.choice(seq)
从非空序列 seq 返回一个随机元素。如果seq
为空,引发IndexError
.
我如何在 .NET 中模拟这一点?
public T RandomChoice<T> (IEnumerable<T> source)
编辑:几年前我在面试时听到过这个问题,但今天这个问题自然地出现在我的工作中。面试问题表述有限制
- “序列太长,无法保存到内存中”
- '你只能循环序列一次'
- “序列没有长度/计数方法”(à .NET IEnumerable)
要创建一个仅迭代源一次并且不必分配内存来临时存储它的方法,您需要计算迭代了多少项,并确定当前项应该是结果的概率:
public T RandomChoice<T> (IEnumerable<T> source) {
Random rnd = new Random();
T result = default(T);
int cnt = 0;
foreach (T item in source) {
cnt++;
if (rnd.Next(cnt) == 0) {
result = item;
}
}
return result;
}
当您看到第一个项目时,应该使用它的概率是 1/1(因为这是您迄今为止看到的唯一项目)。当您处于第二个项目时,它应该替换第一个项目的概率是 1/2,依此类推。
这自然会使用更多的 CPU,因为它为每个项目创建一个随机数,而不仅仅是一个随机数来选择一个项目,正如 dasblinkenlight 指出的那样。您可以检查源是否实现IList<T>
正如丹涛建议的那样,并使用一种实现,该实现使用以下功能来获取集合的长度并按索引访问项目:
public T RandomChoice<T> (IEnumerable<T> source) {
IList<T> list = source as IList<T>;
if (list != null) {
// use list.Count and list[] to pick an item by random
} else {
// use implementation above
}
}
注意:您应该考虑发送Random
实例到方法中。否则,如果您调用该方法两次时间太接近,您将获得相同的随机种子,因为种子是从当前时间创建的。
测试运行的结果,从包含 0 - 9 的数组中选取一个数字 1000000 次,以显示所选数字的分布没有倾斜:
0: 100278
1: 99519
2: 99994
3: 100327
4: 99571
5: 99731
6: 100031
7: 100429
8: 99482
9: 100638
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)