在Python中,我可以这样做:
>>> import random
>>> ints = [1,2,3]
>>> random.choice(ints)
3
在C#中,我做的第一件事就是:
var randgen = new Random();
var ints = new int[] { 1, 2, 3 };
ints[randgen.Next(ints.Length)];
但是这需要索引,ints
的重复也困扰着我。所以,我想出了这个:
var randgen = new Random();
var ints = new int[] { 1, 2, 3 };
ints.OrderBy(x=> randgen.Next()).First();
仍然不是很好,也很有效率。是否有更优雅的方法从IEnumberable获取随机值?
答案 0 :(得分:17)
以下是一些扩展方法:
public static T RandomElement<T>(this IEnumerable<T> enumerable)
{
return enumerable.RandomElementUsing<T>(new Random());
}
public static T RandomElementUsing<T>(this IEnumerable<T> enumerable, Random rand)
{
int index = rand.Next(0, enumerable.Count());
return enumerable.ElementAt(index);
}
// Usage:
var ints = new int[] { 1, 2, 3 };
int randomInt = ints.RandomElement();
// If you have a preexisting `Random` instance, rand, use it:
// this is important e.g. if you are in a loop, because otherwise you will create new
// `Random` instances every time around, with nearly the same seed every time.
int anotherRandomInt = ints.RandomElementUsing(rand);
对于一般IEnumerable<T>
,这将是O( n ),因为这是.Count()
和随机.ElementAt()
调用的复杂性;但是,对于数组和列表都是特殊情况,因此在这些情况下它将是O(1)。
答案 1 :(得分:4)
排序效率会低得多。只需使用Skip(n)和First():
var randgen = new Random();
var ints = new int[] { 1, 2, 3};
ints.Skip(x =&gt; randgen.Next(0,ints.Count()))。First();
ints.ElementAt(x=> randgen.Next(0, ints.Count()));
答案 2 :(得分:3)
不,这基本上是最简单的方法。当然,这只是半随机的,但我认为它符合大多数需求。
编辑:这里的巨大点......
如果您只想从列表中随机选择一个值...那么就这样做:
var myRandomValue = ints[(new Random()).Next(0, ints.Length)];
这是O(1)操作。
答案 3 :(得分:1)
如何简单易读:
ints[randgen.Next(ints.Length)];
说真的,为什么要用lambdas .OrderBy和.First和.Skip等来混淆代码!?