C#:从IEnumerable中获取随机值的优雅代码
在Python中,我可以这样做:C#:从IEnumerable中获取随机值的优雅代码,c#,C#,在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的重复也让我感到困扰。所以,我想到了
>>> 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();
仍然不是很好和有效。有没有更优雅的方法从IEnumerable中获取随机值?没有,这基本上是最简单的方法。当然,这只是半随机的,但我认为它适合大多数需要 编辑:这里有一个巨大的点… 如果您只希望从列表中随机选择一个值。。。那么就这样做:
var myRandomValue = ints[(new Random()).Next(0, ints.Length)];
这是一个O(1)操作。排序的效率要低得多。只需使用Skip(n)和First() 跳过(x=>randgen.Next(0,ints.Count())).First()
简单易读的东西怎么样:
ints[randgen.Next(ints.Length)];
说真的,为什么要用lambdas.OrderBy和.First和.Skip等等混淆代码呢 这里有几个扩展方法供您使用:
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);
public static T random元素(此IEnumerable可枚举)
{
返回enumerable.RandomElementUsing(new Random());
}
公共静态T RandomElementUsing(此IEnumerable可枚举,随机rand)
{
int index=rand.Next(0,enumerable.Count());
返回可枚举的.ElementAt(索引);
}
//用法:
var ints=新的int[]{1,2,3};
int randomInt=ints.RandomElement();
//如果您有一个预先存在的'Random'实例,请使用它:
//这很重要,例如,如果您处于循环中,因为否则您将创建新的
//“随机”实例,每次都有几乎相同的种子。
int-anotherRandomInt=int.RandomElementUsing(兰德);
对于一般的
IEnumerable
,这将是O(n),因为这是.Count()
和随机.ElementAt()
调用的复杂性;但是,数组和列表都是特殊情况,因此在这些情况下,它将是O(1)。假设您的意思是IEnumerable
,但考虑到这个问题,我从IEnumerable
:)中得到了一个LOL。您的IEnumerable
的来源是什么?RandomElement函数似乎就是您要寻找的。@JonH:No,我不想生成随机枚举。什么是“半随机”?random类生成伪随机数,而不是加密强随机数。@Chris我知道什么是伪随机数。我不知道“半随机”是什么意思。而伪随机并不排除它的密码安全性,例如:密码强!=(!pseudo-random)
这可能很容易,但代价很高,因为它会对整个枚举进行排序。有一些著名的随机选择单遍算法,它们对枚举进行递增操作。伪随机!=密码学上很强。如果你能猜出这个值,你就可以破解基于它的密码。From:“这个术语“加密性强”通常用于描述加密算法,与其他一些算法(因此加密性弱)相比,意味着更大的抗攻击性……在这种用法中,这个术语的意思是难以猜测。”最后一个paren应该在.First()之前吗
?为什么要使用.Skip(N).First()
而不是.ElementAt(N)
?你完全正确。ElementAt(N)对于列表将更快。将进行相应的编辑。[]不适用于IEnumerable,这正是海报所要求的。我不认为海报需要基于数组或列表的解决方案,正如您所指出的,这很简单。但是请注意,它会对数据进行两次传递,如果在调用Count
和调用ElementAt
之间数据集发生更改,则可能会导致问题。(此处不是问题,但可能是一般问题)正确;Jon Skeet在的答案可能是这方面最好的答案。如果它查找ElementAt(enum.Count())会不会有问题?假设一个枚举有5项,兰德选择5项。Enum.ElementAt(5)将找不到任何内容,对吗?rand.Next
从不选择其上限。
ints[randgen.Next(ints.Length)];
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);