2

I've started building a super basic 'general knowledge quiz' using Javascript... but I am struggling to come up with an efficient way to get a random question excluding previously chosen questions.

At the moment what I have in place is an array called previous_questions which stores the index of questions that have been previous selected, and a while loop which continues to generate a random value for 'r' if the number already exists in the previous_questions array.

var r = Math.floor(Math.random() * questions.length);
while(previous_questions.indexOf(r) >= 0) {
    r = Math.floor(Math.random() * questions.length);
}

Whilst this is working at the moment, I can't imagine it's an efficient way of doing it and could potentially cause an infinite loop when there are no questions left to select. What would be a more efficient way of doing this? Thanks in advance!

3 Answers3

3

One way to achieve this is to shuffle the questions instead of picking random question at a time.

function shuffle(a) {
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

let questions = ["a", "b", "c", "d", "e", "f"];

shuffle(questions); /* Shuffle the question array */

//Looping thru the shuffled questions
questions.forEach(q => {
    console.log(q);
});

The shuffle function was taken here

Eddie
  • 26,593
  • 6
  • 36
  • 58
0

There are so many ways to do this. One way is to have 2 arrays, 1 with all the unasked questions and the other with all the asked questions. You select a question using a random number from 1 to n (the size of the array of unasked questions), you then remove that question from the list of unasked questions and put it into the list of asked questions. This way you will never get into an infinite loop and in fact you will only ever need to get one random number per iteration. If you are not able to mutate the array of unasked questions then what you can do is right at the start of the operation, make a clone of the array and do what you want with that clone.

Sachin Kainth
  • 45,256
  • 81
  • 201
  • 304
0

You could copy the array and then remove elements randomly:

const left = questions.slice();

function getQuestion(){
  if(!left.length) return;

  return left.splice(Math.floor(Math.random() * left.length), 1)[0];
}
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151