var list = new List<int>(){1,17,18,21,30};
Random rnd = new Random(DateTime.Now.Second);
int r;
do
{
r = rnd.Next(1, 30);
}
while (list.Contains(r));
但我认为这是一个愚蠢的解决方案,任何人都可以给我一个更优化的方法吗?
如果有办法防止Random实例返回已经返回的数字,那就更好了。
如果有人想知道我为什么需要这个,这是改组3字节数组并将它们组合成一个字节数组并生成3字节数组的第一步,它保存索引原始顺序,就像它在原始数组中一样。
答案 0 :(得分:5)
是的,使得它更高效的一件事是使用HashSet<int>
而不是List<int>
查找HashSet比列表快得多(但构造函数的成本会略高一些)对于HashSet)。
此外,如果输入列表始终是相同的数字,则将其移出函数,以帮助减少第一次生成HashSet的成本开销。
由于订单现在很重要,根据我的个人经验(请根据您自己的情况测试和配置文件),在列表中的大约14项之后,将列表转换为HashSet并执行查找比执行查找更快列表本身。
var list = new List<int>(){1,17,18,21,30};
Random rnd = new Random(DateTime.Now.Second);
int r;
//In this example with 5 items in the list the HashSet will be slower do to the cost
// of creating it, but if we knew that the 5 items where fixed I would make this
// outside of the function so I would only have to pay the cost once per program
// start-up and it would be considered faster again due to amortized start-up cost.
var checkHashSet = new HashSet<int>(list);
do
{
r = rnd.Next(1, 30);
}
while (checkHashSet.Contains(rnd.Next(1, 30))); //Shouldent this be "r" not "rnd.Next(1,30)"?
答案 1 :(得分:3)
你是对的,循环不是特别有效。如果考虑有效数字列表的约束,则可以使用some handy extensions来选择数字,而不是无效数字列表。
所以你有无效号码列表:
var list = new List<int>(){1,17,18,21,30};
这意味着有效号码列表的范围是1-30,除了这些。类似的东西:
var validList = Enumerable.Range(1, 30).Except(list);
因此我们可以使用链接答案中的这些扩展名:
public static T RandomElement(this IEnumerable<T> enumerable)
{
return enumerable.RandomElementUsing(new Random());
}
public static T RandomElementUsing(this IEnumerable<T> enumerable, Random rand)
{
int index = rand.Next(0, enumerable.Count());
return enumerable.ElementAt(index);
}
从已知有效数字列表中选择一个随机元素:
var kindOfRandomNumber = Enumerable.Range(1, 30).Except(list).RandomElement();