【问题标题】:Random numbers which have not been previously chosen [duplicate]先前未选择的随机数[重复]
【发布时间】:2016-12-25 18:26:40
【问题描述】:

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

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 循环运行中的随机数相同的情况。我想知道是否有人有一个优雅的解决方案来确保我只生成一个以前没有生成的随机数?我正在考虑填充一个数组并对此进行检查,但这似乎是多余的!

【问题讨论】:

  • 我猜shuffling 就是你要找的。​​span>
  • “优雅”是什么意思?如果要向应用程序添加新逻辑,如何添加数组来检查值是“冗余的”?如果可行,您为什么不完全按照您所描述的那样做?
  • 我认为冗余是一个不好的作品选择。相反,我的意思是优雅,因为它与简约有关。我知道该解决方案会起作用,但我可能不知道更简单的方法。对于一个简单的问题,这似乎是一个很长的解决方案。
  • 如果您有固定数量的practicehistorys,那么您正在寻找shuffle,而不是随机数。

标签: c#


【解决方案1】:

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

【讨论】:

  • 谢谢,我不知道这种方法,绝对是解决这个问题的一种优雅方法。
  • 在这个问题的答案中找到的C#代码:stackoverflow.com/questions/273313/randomize-a-listt-in-c-sharp
  • @NickP,我同意它很优雅。我在工作中多次使用它进行各种类型的测试。这很好,因为它在选择中是“公平的”(不偏不倚的)。
  • @MarkWilkins 绝对比每次都检查已经选择的内容更简洁。非常感谢!
【解决方案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;
}

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

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

【讨论】:

  • 我讨厌那些 filler 的答案。
  • @I4V 对不起,答案不再是填充物,而是两种数字生成方法的实际实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 2017-10-25
  • 2019-05-05
  • 1970-01-01
  • 2014-07-05
相关资源
最近更新 更多