Home > Net >  C# Creating a List of Class Elements to use multiple times
C# Creating a List of Class Elements to use multiple times

Time:11-11

Please excuse my noobness regarding this language, I am very much a beginner. I've been tasked with creating a Quiz Maker and I'm stuck on how I am supposed to put some of my class elements into a List. The reason I need to put these into a list is because I don't want to handle each user inputted answer separately, rather in a list and have everything dependant on the list size and set a limit for how many answers I want to store in it. Any help would be hugely appreciated.

Here is my class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Quiz_Maker
{
    public class QuestionAndAnswers

    {
        public string userQuestion { get; set; }

        List<string> QnAList = new List<string>();

        public string falseAnswerOne { get; set; }          //TODO: this could maybe perhaps possilby be a list of string
        public string falseAnswerTwo { get; set; }          //TODO: this could maybe perhaps possilby be a list of string
        public string falseAnswerThree { get; set; }        //TODO: this could maybe perhaps possilby be a list of string
        public string correctAnswer { get; set; }           //TODO: this could maybe perhaps possilby be a list of string

        private int correctAnswerIndex;                     
    }
}

Here is my object method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Quiz_Maker
{
    public static class UserInterface
    {

      public static QuestionAndAnswers GetQuestionAndAnswers()
        {
            QuestionAndAnswers UserQnA = new QuestionAndAnswers();

            string userQuestion;
            string correctAnswer;
            string falseAnswerOne;
            string falseAnswerTwo;
            string falseAnswerThree;

            Console.WriteLine("Please type your question: ");
            UserQnA.userQuestion = Console.ReadLine();

            Console.WriteLine("Please type the correct answer: ");
            UserQnA.correctAnswer = Console.ReadLine();

            Console.WriteLine("Please type your first false answer: ");
            UserQnA.falseAnswerOne = Console.ReadLine();

            Console.WriteLine("Please type your second false answer: ");
            UserQnA.falseAnswerTwo = Console.ReadLine();

            Console.WriteLine("Please type your third false answer: ");
            UserQnA.falseAnswerThree = Console.ReadLine();

            return UserQnA;
        }
    }
}

I've googled this topic to death and have not found anything that makes sense.

CodePudding user response:

I would probably set up a Parent Child relationship. maybe something like this.

public class QuestionAndAnswers{
     public string QuestionText { get; set; }
     public IEnumerable<Answer> Answers { get; set; }
}

public class Answer{
    public string AnswerText {get; set;}
    public bool CorrectAnswer {get; set;}   
    
}

then you can populate your List of Question and answers

List<QuestionAndAnswers> questionAndAnswers = new List<QuestionAndAnswers>
        {
            new QuestionAndAnswers{
                QuestionText = "What color is the sky",
                Answers = new List<Answer>{
                    new Answer{ AnswerText = "Green", CorrectAnswer = false},
                    new Answer{ AnswerText = "Yellow", CorrectAnswer = false},
                    new Answer{ AnswerText = "Purple", CorrectAnswer = false},
                    new Answer{ AnswerText = "Blue", CorrectAnswer = true}  
                    }
                },
             new QuestionAndAnswers{
                QuestionText = "What color is the grass",
                Answers = new List<Answer>{
                    new Answer{ AnswerText = "Green", CorrectAnswer = true},
                    new Answer{ AnswerText = "Yellow", CorrectAnswer = false},
                    new Answer{ AnswerText = "Purple", CorrectAnswer = false},
                    new Answer{ AnswerText = "Blue", CorrectAnswer = false} 
                    }
                }
            };

CodePudding user response:

I would model the class with a list of false and a list of correct answers, i.e. something like

public class QuestionAndAnswers {
        public string UserQuestion { get; set; }
        public string[] FalseAnswers { get; set; }
        public string[] CorrectAnswers { get; set; }
}

That lets you have arbitrary many answers, and multiple correct answers if you like. But you might want to add some validation to ensure that there is at least one correct answer.

To post a question you would merge the list and shuffle them, so that the order is randomized each time. To check if an answer is correct you can just check if the string exist in the correct-list. For example:

public string[] GetAnswers()
{
    var all = FalseAnswers.Concat(CorrectAnswers).ToArray();
    all.Shuffle();
    return all;
}
public bool IsCorrect(string answer) => CorrectAnswers.Contains(answer);

You can then make a method to actually ask your question, putting it all together:

public class QuestionAndAnswers {
    public string UserQuestion { get; set; }
    public string[] FalseAnswers { get; set; }
    public string[] CorrectAnswers { get; set; }

    public string[] GetAnswers()
    {
        var all = FalseAnswers.Concat(CorrectAnswers).ToArray();
        all.Shuffle();
        return all;
    }

    public bool IsCorrect(string answer) => CorrectAnswers.Contains(answer);

    public bool Ask()
    {
        Console.WriteLine(UserQuestion);
        var answers = GetAnswers();
        for (int i = 0; i < answers.Length; i  )
        {
            Console.WriteLine($"{i}: {answers[i]}");
        }

        for (int i = 0; i < 3; i  )
        {
            while (!int.TryParse(Console.ReadLine(), out var index) || index < 0 || index >= answers.Length)
            {
                if (!IsCorrect(answers[index]))
                {
                    Console.WriteLine("Correct!");
                    return true;
                }
                else
                {
                    Console.WriteLine("False!");
                }
            }
        }
        return false;
    }
}

CodePudding user response:

Your problem is that you are storing the answers in both a list and with fields. You have to pick one or the other. Or maybe not. After some thinking, you might actually be on the correct path here. Let me explain.

I think what would make sense here is to have one string field of the correct answer and a list of the remaining incorrect answers. This way you do not need to store the index of the correct answer, which means the order of the answers does not need to be fixed.

public class QuestionAndAnswers
{
    private readonly string _correctAnswer;

    public QuestionAndAnswers(string question, string correctAnswer)
    {
        Question = question;
        CorrectAnswer = correctAnswer;
        IncorrectAnswers = new List<string>();
    }
    public string Question { get; }
    public string CorrectAnswer { get; set; }
    public List<string> IncorrectAnswers { get; }

}

you define an instant by the question and correct answer (which always need to go together) and then later you can add other answers as needed.

public static UserInterface
{
    // ...
    public static QuestionAndAnswers NewQuestionAndAnswers()
    {
        Console.WriteLine("Please type your question: ");
        string userQuestion = Console.ReadLine();

        Console.WriteLine("Please type the correct answer: ");
        string correctAnswer = Console.ReadLine();

        Console.WriteLine("Please type your first false answer: ");
        string falseAnswerOne = Console.ReadLine();

        Console.WriteLine("Please type your second false answer: ");
        string falseAnswerTwo = Console.ReadLine();

        Console.WriteLine("Please type your third false answer: ");
        string falseAnswerThree = Console.ReadLine();

        QuestionAndAnswers userQnA = new QuestionAndAnswers(userQuestion, correctAnswer);
        userQnA.IncorrectAnswers.AddRange(new string[] { falseAnswerOne, falseAnswerTwo, falseAnswerThree });

        return userQnA;
    }
}

In the interest of fairness, the order of the answers is determined at a later time. This is done with the GetShuffledAnswers() function.

Then to take the quiz, you make a list with the correct and incorrect answers and shuffle it. Then return the shuffled list, as well as the index of the correct answer as an out parameter (an argument that gets assigned when the function is called). So add the following function to QuestionAndAnswers.

public class QuestionAndAnswers
{
    // ...
    static readonly Random rng = new Random();
    public string[] GetShuffledAnswers(out int correctIndex)
    {
        var list = IncorrectAnswers.ToList();
        list.Add(CorrectAnswer);
        list.Sort((x, y) => rng.Next(2) * 2 - 1);   // shuffles list
        correctIndex = list.IndexOf(CorrectAnswer);
        return list.ToArray();
    }
}

And now for an example of how to use the above code:

public static UserInterface
{
    // ...
    public static bool AskQuestion(QuestionAndAnswers userQnA)
    {
        string[] answers = userQnA.GetShuffledAnswers(out int correctIndex);

        Console.WriteLine($"Question: {userQnA.Question}");
        Console.WriteLine("Answers:");
        for (int i = 0; i < answers.Length; i  )
        {
            Console.WriteLine($"  {i   1}. {answers[i]}");
        }
        int userPick = 0;
        do
        {
            Console.WriteLine("Pick one answer:");
            string input = Console.ReadLine();
            int.TryParse(input, out userPick);
        } while (userPick<=0);

        return userPick - 1 == correctIndex;
    }
}

Note that the correct index us from 0..3 and the user picks their answer with numbers 1..4 so that is why the check is userPick - 1 == correctIndex.

with some example testing output:

Please type your question:
The color of the sky is
Please type the correct answer:
Blue
Please type your first false answer:
Orange
Please type your second false answer:
Black
Please type your third false answer:
Yellow
Question: The color of the sky is
Answers:
  1. Orange
  2. Blue
  3. Black
  4. Yellow
Pick one answer:
2
Correct :-)
  • Related