获得随机数的更快捷方式

时间:2017-07-24 17:55:29

标签: c#

我遇到了问题

我需要获得随机数字,但我已经拥有的数字除外。

我的代码:

List<int> current_numbers = repository.GetCurrentNumbers();            
Random rnd = new Random(42);
var new_values = Enumerable.Range(10000000,99999999)
    .Except(current_numbers)
    .OrderBy(o=> rnd.Next())
    .Take(amount)
    .ToList();

但是这段代码非常缓慢

当我尝试使用select而不是OrderBy时 - 我得到了DUPLICATES。 就我而言,它必须没有重复。

更新: 使用OrderBy - 我的内存有问题:)

范围必须像1M - 99M 谢谢。

3 个答案:

答案 0 :(得分:0)

使用HashSet<T>代替List,然后使用Contains进行测试 - 如果你看一眼Reference Source,你会注意到{{1}将这些现有数字构建为Except

由于Set尝试对整个集合进行排序,因此您可以使用OrderBy完全失去延迟执行的枚举的好处 - 而是使用常规循环并生成随机数

OrderBy

或者自己编写发电机

var random = new Random();  // Default constructor or you'll get the same sequence because of a constant seed
var result = new HashSet<int>();
var currentNumbers = new HashSet<int>(repository.GetCurrentNumbers());

while(result.Count < amount)
{
    var next = random.Next(1000000,99000000);
    if(currentNumbers.Contains(next)) continue;

    result.Add(next);
}

答案 1 :(得分:0)

由于您需要来自如此大范围的数字,因此您可能希望使用$("li.dropdown").hover( function () { $(this).find("i").addClass("gxcpl-fa-rotate-45"); }, function () { $(this).find("i").removeClass("gxcpl-fa-rotate-45"); } ); 来消除重复数据。

HashSet

HashSet<int> current_numbers = new HashSet<int>(repository.GetCurrentNumbers()); HashSet<int> newValues = new HashSet<int>(); while (newValues.Count < amount) { var next = rnd.Next(10000000,99999999); if (!current_numbers.Contains(next)) newValues.Add(next); } 转换为current_numbers会加快此过程,因为如果HashSet未存储为Contains,则O(n)的调用将花费current_numbers时间HashSet

答案 2 :(得分:0)

为了避免创建庞大的数字列表,您可以跟踪您拥有的数字,并随机选择下一个数字的来源。首先,您需要使用已编号的有序列表。然后添加下限和上限。然后跟踪下限和上限的索引。然后迭代,直到你有足够的数字,每次随机选择下限和上限索引之间的索引。检查该索引处和下一个索引处的数字之间的差异是否为1,如果是,则增加索引直到它不是或者您达到上限。如果上限被击中,那么只需向上走,然后重试。当您确实在使用的数字中找到间隙时,在间隙中随机选择一个数字并将其添加到返回列表和正确索引处的已使用列表中。然后确保在需要时向上走下限索引。

var used = repository.GetCurrentNumbers().OrderBy(x => x).ToList();
used.InsertAt(0, 999999) // This is the lower bounds;
used.Add(100000000); // This is the upper bounds;
var random = new Random();

var values = new List<int>();
int lowerIndex = 0; 
int upperIndex = used.Length - 1;
while(values.Count < amount) {
    int ind = random.Next(lowerIndex, upperIndex); 
    while(ind < upperIndex && used[ind+1] - used[ind] == 1) ind++;
    if(ind == upperIndex){
        while(used[upperIndex] - used[upperIndex-1] == 1) upperIndex--;
        continue;
    }

    int val = random.Next(used[ind]+1, used[ind+1]);
    values.Add(val);
    used.InsertAt(ind+1, val);

    while(used[lowerIndx+1] - used[lowerIndex] == 1) lowerIndex++;
}

如果amount不是一个非常大的数字且你的整体范围很大而且初始使用的数字也很稀疏,那么效果最好。