【问题标题】:Randomisation of multidimensional array in C#C#中多维数组的随机化
【发布时间】:2011-10-14 12:02:58
【问题描述】:

对于一个迷你项目,我正在制作一个测验程序 我当前(相关)代码如下:

static Random _r = new Random();        
static int Quiz()
{
    string[,] QAndA = {
        {"What is the capital of France", "Paris"},
        {"What is the capital of Spain", "Madrid"},
                ...
        {"What is the captial of Russia", "Moscow"},
        {"What is the capital of Ukraine", "Kiev"},
    };

    for (int i = 0; i < NUM_QUESTIONS; i++)
    {
        int num = _r.Next(QAndA.GetLength(0) / 2);
        Question(QAndA[num, 0], QAndA[num, 1]);
    }
}

现在,这样做的明显问题是随机数可以重复,这意味着问题可以重复。

现在,我的老师(是的,这是学校的事情)告诉我要寻找洗牌算法,但我没有找到像我用过的那样适用于多维数组的任何算法。

我是一个相当新的 c# 程序员,但我有 c++ 经验 并且该程序是一个命令行程序(目前:)),如果这很重要/有帮助

那么,问题是,将多维数组重新排序/改组为随机顺序的最佳方法是什么?

【问题讨论】:

  • 与您的问题无关,我建议创建一个带有QuestionAnswer 属性的Question 类。

标签: c# random multidimensional-array


【解决方案1】:

您正在寻找错误的问题。使用交错数组代替多维数组(很少使用,因为几乎不支持)。

string[][] questions = new[] { 
    new [] {"What is the capital of France", "Paris"}, 
    new [] {"What is the capital of Spain", "Madrid"},
    new [] {"What is the captial of Russia", "Moscow"},
    new [] {"What is the capital of Ukraine", "Kiev"},
};

// use: questions[0][0] (question), questions[0][1] (answer), questions[1][0] (question)...

或者(更好)创建一个包含两个成员的类,QuestionAnswer

class QuestionAndAnswer
{
    public string Question { get; protected set; }
    public string Answer { get; protected set; }

    public QuestionAndAnswer(string question, string answer)
    {
        this.Question = question;
        this.Answer = answer;
    }
}

QuestionAndAnswer[] questions = new QuestionAndAnswer[] { 
    new QuestionAndAnswer("What is the capital of France", "Paris"),
    new QuestionAndAnswer("What is the capital of Spain", "Madrid"),
    // ...
};

// use: questions[0].Question, questions[0].Answer...

然后您可以使用Knuth 算法:-)

从那里引用:

To shuffle an array a of n elements (indexes 0..n-1):
  for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ i
       exchange a[j] and a[i]

在 C# 中,算法类似于

Random rnd = new Random();

for (int i = questions.Length - 1; i >= 1; i--)
{
    // Random.Next generates numbers between min and max - 1 value, so we have to balance this
    int j = rnd.Next(0, i + 1);

    if (i != j)
    {
        var temp = questions[i];
        questions[i] = questions[j];
        questions[j] = temp;
    }
}

【讨论】:

  • 课堂评论+1。这根本不适合多维数组。它应该是一个简单的类列表。
  • 这听起来也像是家庭作业,所以他将使用他被指示使用(或教授)的工具。
  • 感谢班级的想法听起来不错,但我不确定如何将 2 个成员链接在一起,就像我可以使用数组一样
  • @AnthonyPegram sort-of-not-quite-homework :) 我现在正在课堂上做的事情远远超过我们现在在课堂上所做的事情 - 从技术上讲,我们还没有得到数组 :)
  • @LordAro 你有什么问题?您使用 [] 访问问题数组,因此 questions[0] 将为您提供第一个 questionAndAnswer,questions[1] 第二个......然后您访问诸如 questions[0].Question 和 questions[0] 之类的成员。回答
【解决方案2】:

我建议使用“多维”数组,如果它是......不是多维数组。

我的建议:(看它住在这里http://ideone.com/NsjfM

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    struct QA { public string Q, A; }

    static Random _r = new Random();        
    static int Quiz()
    {
        var QAndA = new QA[] {
            new QA { Q = "What is the capital of France"  , A = "Paris"}, 
            new QA { Q = "What is the capital of Spain"   , A = "Madrid"}, 
            //  ...
            new QA { Q = "What is the captial of Russia"  , A = "Moscow"}, 
            new QA { Q = "What is the capital of Ukraine" , A = "Kiev"}, 
        };

        foreach (var qa in QAndA.OrderBy(i => _r.Next()))
        {
            Question(qa.Q, qa.A);
        }

        return 0;
    }

    public static void Main(string[] args)
    {
        int n = Quiz();
    }

    private static void Question(string q, string a)
    {
        Console.WriteLine("Q. {0}", q);
        Console.WriteLine("A. {0}", a);
    }

}

【讨论】:

    【解决方案3】:
    maybe better (without shouffling, without repeatable questions):       
    
    
    
    class QuizQuestion
    {
    public string Question {get; set;}
    public string Answer {get; set;}
    }
    
    static Random _r = new Random();        
            static int Quiz()
            {
                QuizQuestion[] QAndA = new QuizQuestion[] {
                    new QuizQuestion() {Question = "What is the capital of France", Answer = "Paris"},
                    new QuizQuestion() {Question = "What is the capital of Spain", Answer ="Madrid"},
                            ...
                    new QuizQuestion() {Question = "What is the captial of Russia", Answer ="Moscow"},
                    new QuizQuestion() {Question = "What is the capital of Ukraine", Answer ="Kiev"},
                };
    
                var questions = QAndQ.ToList();
                for (int i = 0; i < NUM_QUESTIONS; i++)
                {
                    int num = _r.Next(questions.Length / 2);
                    Question(questions[num].Question, questions[num].Answer);
                    questions.Remove(questions[num]);
                }
            }
    

    【讨论】:

    • List.Remove() 是 O(n),将“挑选”的问题存储在一个集合中然后仅在集合具有一定大小时才返回可能会更快。
    • 从性能的角度来看,最好的方法是生成带有布尔值的附加列表,其中包含有关此会话中使用问题的信息。使用问题时,usage[questionIndex] = true。在所有步骤中,您将在 0 到 questionCount - i 的范围内排列数字,并通过 usageQuestionList、跳过的位置检查问题的使用情况,其中 questionUsageList[j] 等于 true;
    • 两者都是 O(1),所以这取决于开销。
    【解决方案4】:

    实际上你正在重新排列一个维度数组,因为你不应该打乱答案;)最简单的算法可能是:

       foreach array index
          switch with random index in array
    

    【讨论】:

      【解决方案5】:

      一种不需要您重新排列数组并且如果您只需要选择几个问题会更快的方法是将您选择的问题存储在一个集合中。

      继续生成随机数并将该索引处的问题添加到集合中,一旦集合的大小正确,就返回它。

      您的循环将类似于:

      var questions = new HashSet<Question>();
      while (questions.Count < numberOfQuestionsRequired)
      {
        questions.Add(questionArray[_r.Next()])
      }
      

      HashSet&lt;&gt;.CountHashSet&lt;&gt;.Add() 都是 O(1),所以限制因素是有多少随机数发生冲突。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-31
        • 1970-01-01
        • 1970-01-01
        • 2018-04-30
        相关资源
        最近更新 更多