简体   繁体   中英

Trying to choose random questions from an array, with answers in a separate array?

I'm trying to make a program that will ask you random questions from an array. You answer them, and it tells you whether or not you are correct.

I have a questions array:

String[] questions = {"Type A", "Type B", "Type C", "Type D", "Type E", "Type F", "Type G"};

and then I have an answers array. they correspond with each other, so answers[0] is the answer to questions[0]

 String[] answerKey = {"A", "B", "C", "D", "E", "F", "G"};
 int questionNum = 0; //Used as a counter for the questions.

Here is my code attempt.

public void setUpQuestion() {
    String[] answers = new String[4]; //An array of possible answers.
    ArrayList<Integer> usedNumbers = new ArrayList<Integer>(); //An Arraylist of question positions.
    ArrayList<Integer> usedQuestions = new ArrayList<Integer>(); //A copy of the usednumbers arraylist


    for (int i = 0; i < answerKey.length; i++) //Add 0 through 6 to this arraylist, represents the questions
        usedNumbers.add(i);
    Collections.shuffle(usedNumbers); // Shuffle the arrayList into a random order
    usedQuestions = usedNumbers; //Copy the array

    for (int a = 0; a < answers.length; a++) { // This for loop should add random answers to the answers array
        if (a == 0) {//For the first time around, add the correct answer into the array
            answers[a] = answerKey[usedQuestions.get(questionNum)]; //answers[0] = the correct answer to the question
            usedNumbers.remove(questionNum); //remove it from the copied array, so we don't accidentally use it twice
        } else if (a != 0) { //For the rest of the spots, randomly pick answers that are wrong
                answers[a] = answerKey[usedNumbers.get(0)];//pick a random answer that is next
                usedNumbers.remove(0);//Remove it so it isnt used again

        }
    }
    lblQuestion.setText(questions[usedQuestions.get(questionNum)]); // Set the label to the question
    shuffleArray(answers);//shuffle the array of answers
    btnA.setText(answers[0]); //set the button to one of the answers, etc;
    btnB.setText(answers[1]);
    btnC.setText(answers[2]);
    btnD.setText(answers[3]);

}

Hopefully I've commented it thoroughly enough so you know what the code is doing

This seems like it should work in theory, however, when I run it, this happens: 没有列出正确的答案 There is no correct answer listed.

If anyone could help me figure out why this isn't working, I would really appreciate it.

Thank you!


Edit:

I have tried a different approach that may work better. I created a Question object that has the parameters of String question, String answer.

So, I made a bunch of new Question objects

public int questionNum = 0; //this is a global variable
Question a = new Question("Type A", "A");
Question b = new Question("Type B", "B");
Question c = new Question("Type C", "C");
Question d = new Question("Type D", "D");
Question e = new Question("Type E", "E");
Question[] questionBank = {a, b, c, d, e};
ArrayList<Question> questionArray = new ArrayList<Question>();

Here's my new attempt at the code:

for (int i = 0; i < questionBank.length; i++) questionArray.add(questionBank[i]);//Add all question objects to an arraylist

    String[] answers = new String[4];//possible answers
    Collections.shuffle(questionArray);//randomize thequestion array,

    for (int a = 0; a < answers.length; a++) {
        if (a == 0) {//First time around, add the correct answer to the array
            answers[a] = questionArray.get(questionNum).getA();//getA() method gets the answer from the question array
        } else if (a != 0) {
                answers[a] = questionArray.get(a).getA();
                questionArray.remove(a);
        }
    }

    lblQuestion.setText(questionArray.get(questionNum).getQ()); //Gets the current question
    btnA.setText(answers[0]);
    btnB.setText(answers[1]);
    btnC.setText(answers[2]);
    btnD.setText(answers[3]); //set the answers on the buttons
    questionArray.remove(questionNum);

Change

usedQuestions = usedNumbers;

to

usedQuestions = new ArrayList<>(usedNumbers);

How this works

Observer the following example:

Integer h = 3;
Integer j = h;
h++;
System.out.println(j);

What will the output be? As you might think, it's 3 .

  1. h got the value of 3.
  2. j got the same value as h .
  3. h was changed.
  4. j wasn't changed.
  5. j is h 's previous value.

Sure enough, you write this:

ArrayList<Integer> usedNumbers = new ArrayList<Integer>();
ArrayList<Integer> usedQuestions = new ArrayList<Integer>();
for (int i = 0; i < 3; i++) // add 0, 1, 2
    usedNumbers.add(i);

usedQuestions = usedNumbers;
usedNumbers.remove(0);
System.out.println(usedQuestions);

thinking that the output will be [0, 1, 2] . Wrong! Let's see the difference from the first case.

  1. usedNumbers got the values [0, 1, 2] .
  2. usedQuestions got the same value as usedNumbers ? NOPE! usedQuestions got the same reference as usedNumbers . (explanation below)
  3. usedNumbers was changed.
  4. usedQuestions was changed.
  5. usedQuestions has the changed value of [1, 2] .

In Java, most objects are reference types . It means that what the variable it is holding is a reference to the value (a pointer to the address in memory). When you wrote usedQuestions = usedNumbers what you did is give the "arrow" which is pointing to the list [0, 1, 2] to usedQuestions . Now, when you change the list (with remove ), you change the value of the list, but every variable which holds a reference to that list will give the same modified list .

The first example worked as expected because int is a primitive type where the variable holds a "real" value, and not a pointer to it. In this case changing the number (with ++ ) actually changed the value of the number, but all other numbers were remained unchanged.

This goes hand in hand with shallow copy vs deep copy . There are more questions on this site and articles about it than I'd care to link, so just Google it and you'll get more than what you bargained for. The short explanation is that shallow copy only copies the reference which is what you did, while deep copy makes a "real" copy of the value. A "real" copy means that

  1. Changes to one copy won't affect the other.
  2. You are using twice the memory because you are keeping the same data in 2 different addresses.

The line usedQuestions = new ArrayList<>(usedNumbers); essentially makes a deep copy of the list (only because it's a list of Integer ), while usedQuestions = usedNumbers is a shallow copy.

There are quite a few fine points I didn't address here, nor was I too technically accurate, but I'm trying to explain a subtle and important topic simply.

If you understood this, you might have understood that the line

ArrayList<Integer> usedQuestions = new ArrayList<Integer>();

can just be

ArrayList<Integer> usedQuestions;

The reason is that you don't need to initialize the list at this point in the code as it will be initialized later with new ArrayList<>(usedNumbers) . To be specific, in your original code you "threw away" the pointer to the original empty list in the right hand side of

ArrayList<Integer> usedQuestions = new ArrayList<Integer>();

when you gave usedQuestions the pointer to the list in the right hand side of

ArrayList<Integer> usedNumbers = new ArrayList<Integer>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM