Рандомизация многомерного массива в C # - PullRequest
0 голосов
/ 14 октября 2011

Для мини-проекта я делаю программу викторины. Мой текущий (релевантный) код выглядит следующим образом:

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 ++, и эта программа является программой командной строки (на данный момент :)), если это имеет значение / помогает

Итак, вопросКаков наилучший способ переупорядочения / перетасовки многомерного массива в случайном порядке?

Ответы [ 5 ]

4 голосов
/ 14 октября 2011

Вы смотрите не на ту проблему. Вместо многомерного массива (что-то довольно редко используется из-за малой поддержки) используйте зубчатый массив.

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)...

или (лучше) создать класс с двумя членами, Question и Answer.

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 голос
/ 14 октября 2011
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]);
            }
        }
1 голос
/ 14 октября 2011

Я предлагаю НЕ , используя 'многомерный' массив, если он ... не многомерный массив.

Мое предложение: (см. live here 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);
    }

}
0 голосов
/ 14 октября 2011

Метод, который не требует перестановки массива и который будет быстрее, если вам нужно только выбрать несколько вопросов, - это сохранить выбранные вопросы в наборе.

Продолжайте генерировать случайные числа и добавлять вопрос по этому индексу в набор, как только набор будет иметь правильный размер, верните его.

Ваш цикл будет выглядеть примерно так:

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

HashSet<>.Count и HashSet<>.Add() - оба O (1), поэтому ограничивающим фактором будет количество случайных чисел.

0 голосов
/ 14 октября 2011

на самом деле вы переопределяете одномерный массив, потому что вы не должны перемешивать ответы;) простейший алгоритм может быть:

   foreach array index
      switch with random index in array
...