#c# #random #multidimensional-array
#c# #Случайный #многомерный массив
Вопрос:
Для мини-проекта я создаю программу викторины, мой текущий (соответствующий) код выглядит следующим образом:
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 , и программа представляет собой программу командной строки (на данный момент :)), если это имеет значение / помогает
Итак, вопрос в том, каков наилучший способ переупорядочения / перетасовки многомерного массива в случайном порядке?
Комментарии:
1. Не связанный с вашим вопросом, я бы предложил создать
Question
класс с aQuestion
иAnswer
свойством.
Ответ №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)...
или (лучше) создайте класс с двумя членами, 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...
Затем вы могли бы использовать алгоритм Кнута 🙂
Цитирую оттуда:
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. 1 за комментарий к классу. Это совсем не подходит для многомерного массива. Это должен быть простой список классов.
2. Это также звучит как домашнее задание, поэтому он будет использовать инструменты, которые ему было поручено использовать (или которым его научили).
3. спасибо за это, идея класса звучит хорошо, но я не уверен, как связать 2 элемента вместе, как я могу сделать с массивами
4. @AnthonyPegram своего рода не совсем домашнее задание 🙂 я иду намного выше того, что мы делаем в классе в данный момент — мы технически еще не добрались до массивов 🙂
5. @LordAro В чем ваша проблема? Вы получаете доступ к массиву вопросов с помощью [] , поэтому questions[0] даст вам первый вопрос и ответ, questions[1] — второй … а затем вы получаете доступ к элементам, таким как questions[0].Вопрос и вопросы [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]);
}
}
Комментарии:
1. List<>.Remove() равно O(n), возможно, было бы быстрее сохранить «выбранные» вопросы в наборе, а затем возвращать только тогда, когда набор имеет определенный размер.
2. С точки зрения производительности лучшим будет сгенерировать дополнительный список со значениями bool, который будет содержать информацию о вопросе использования в этом сеансе. Когда используется вопрос, тогда usage[questionIndex] = true . На всех этапах вы будете ранжировать число из диапазона 0 в questionCount — i и проверять использование итерации вопроса с помощью usageQuestionList, пропущенный вариант, где questionUsageList[j] равно true;
3. Оба равны 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<>.Count
и HashSet<>.Add()
оба являются O (1), поэтому ограничивающим фактором будет то, сколько случайных чисел сталкивается.