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

0

これを解決するには 2 つの方法があります。番号が既に使用されているかどうかを確認するか、番号を事前に生成して、格納されている順序をランダム化し、「シャッフルされた順序」でリストから取り出します。

最初のアプローチは、合計で必要な数がわからない場合、または非常に大きな数のプールがあり、同じ数を複数回見つけることで衝突が発生する可能性が低い場合に適しています。この欠点は、使用可能な合計数のパーセンテージが多く使用されるほど、次の数生成の実行が遅くなります。

//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;
}

2 番目のアプローチは、必要なオブジェクトの数が正確にわかっている場合、または選択できる選択肢が少ない場合に適しています。

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 に答える