0

以下代码部分按我的意愿工作

for (int i = 1; i <= practicehistory.TotalNumQuestions; i++)
{
    query = from a in db.Questions
            where a.CategoryId == practicehistory.CategoryId
            orderby a.QuestionId
            select a;
    randomNumber = random.Next(1, count + 1);
    int qNum = query.Skip(randomNumber - 1).First().QuestionId;
    asked.QuestionId = qNum;
    asked.OrderAsked = i;
    db.AskedHistories.Add(asked);
    db.SaveChanges();
}

但是,我偶尔会遇到随机数与前一次 for 循环运行中的随机数相同的情况。我想知道是否有人有一个优雅的解决方案来确保我只生成一个以前没有生成的随机数?我正在考虑填充一个数组并对此进行检查,但这似乎是多余的!

4

2 回答 2

7

这样做的一种方法是生成可能值的数组(例如,整数 1 到 N 的数组),然后对它们进行混洗,然后根据需要遍历尽可能多的混洗值。如果您对“通过示例”进行编码感兴趣,那么快速的 Google 搜索会产生多个 Fisher-Yates shuffle 的 C# 实现。

于 2013-09-13T20:52:08.507 回答
0

有两种方法可以解决这个问题,检查数字是否已被使用,或者预先生成数字随机化它们存储的顺序,并以“随机顺序”将它们从列表中取出。

当您不知道总共需要多少个数字或者您有一个非常大的数字池并且您不太可能因多次找到相同的数字而发生冲突时,第一种方法会更好。这样做的缺点是,使用的可用总数的百分比越多,下一个数字生成运行的速度就越慢。

//This function will run slower and slower until all numbers have been used and then it will throw a InvalidOperationExecption. 
//You could get a InvalidOperationExecption early if you reuse the ISet for multiple ranges.
public static int NextUnused(this Rand rand, int minValue, int maxValue, ISet<int> usedNumbers)
{
    if(usedNumbers.Count >= maxValue - minValue)
        throw new InvalidOperationExecption("All possible numbers have been used");

    int number;
    do
    {
       number = rand.Next(minValue, maxValue);

    } while(!usedNumbers.Add(number)) //if we have seen the number before it will return false and try again.

    return number;
}

如果您确切地知道需要多少对象,或者有一小部分可供选择的可能选项,则第二种方法会更好。

public class RandomRange
{

    public RandomRange(int start, int count) : this(start, count, new Rand())
    {
    }

    public RandomRange(int start, int count, Rand randSource)
    {
        var numberList = new List<int>(Enumerable.Range(start, count);

        Shuffle(numberList);

        _numbers = new Queue<int>(numberList);
    }

    //Will throw a InvalidOperationExecption when you run out of numbers.
    public int GetNextNumber()
    {
        return _numbers.Dequeue();
    }

    private static void Shuffle(List<int> list)
    {
         throw new NotImplementedException("An exercise for the reader");
    }

    private Queue<int> _numbers;
}
于 2013-09-13T20:54:39.377 回答