Pepe
Pepe

Reputation: 71

Shuffle the array of objects without picking the same item multiple times

I have an array of questions that I want to randomize and put into a quiz. However currently it can choose the same question twice and put it in the quiz twice. If I want to delete the question after it has been pushed to a new array, without knowing its index how can I remove it?

My code that i tried was this

var index = questionsArrayCopy.findIndex(function(item, i){return item.question === randomQuestion});
questionsArrayCopy.splice(index)

But it didn't work and I had no errors

My current code is below:

const myQuestions = [
  {
    question: 'What is 37 x 89?',
    answers: [
      { text: '6989', correct: false },
      { text: '3293', correct: true },
      { text: '2400', correct: false },
      { text: '9870', correct: false }
    ]
  },
  {
    question: 'What year is the great fire of london?',
    answers: [
      { text: '1666', correct: true },
      { text: '1888', correct: false },
      { text: '1600', correct: false },
      { text: '1566', correct: false }
    ]
  },
  {
    question: 'Is web development fun?',
    answers: [
      { text: 'Kinda', correct: false },
      { text: 'YES!!!', correct: true },
      { text: 'Um no', correct: false },
      { text: 'IDK', correct: false }
    ]
  },
  {
    question: 'What is 4 * 2?',
    answers: [
      { text: '6', correct: false },
      { text: '8', correct: true }
    ]
  },
]

function getRandomNumberBetween(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

const GetRandomQuestionFromArray = (array) => {
   const randomIndex = getRandomNumberBetween(0, array.length);
   return array[randomIndex];
}

const GetRandomQuestionsArray = (howManyQuestions) => {
  const questionsArrayCopy = [...myQuestions];
  const finalQuestionArray = [];

  for (let i = 0; i < howManyQuestions; i++) {
      const randomQuestion = GetRandomQuestionFromArray(questionsArrayCopy);
      finalQuestionArray.push(randomQuestion);
  }
  return finalQuestionArray;
}

const questions = GetRandomQuestionsArray(3);
console.log(questions)

If I want to stop duplicate questions from entering the final array(questions) and just choose random ones from the other array(myQuestions) how would I do that?

Upvotes: 1

Views: 667

Answers (4)

Jamiec
Jamiec

Reputation: 136164

You already had the index of the item you picked, you just threw it away:

const GetRandomQuestionFromArray = (array) => {
   const randomIndex = getRandomNumberBetween(0, array.length); //<-- here it is!!
   return array[randomIndex];
}

So seeing as that method really doesn't help you much just move the logic to the method calling it, and then use splice to remove that index:

const GetRandomQuestionsArray = (howManyQuestions) => {
  const questionsArrayCopy = [...myQuestions];
  const finalQuestionArray = [];

  for (let i = 0; i < howManyQuestions; i++) {
      const randomIndex = getRandomNumberBetween(0, questionsArrayCopy .length);
    
      const randomQuestion = questionsArrayCopy.splice(randomIndex,1);
      finalQuestionArray.push(randomQuestion[0]);
  }
  return finalQuestionArray;
}

Live example:

const myQuestions = [
  {
    question: 'What is 37 x 89?',
    answers: [
      { text: '6989', correct: false },
      { text: '3293', correct: true },
      { text: '2400', correct: false },
      { text: '9870', correct: false }
    ]
  },
  {
    question: 'What year is the great fire of london?',
    answers: [
      { text: '1666', correct: true },
      { text: '1888', correct: false },
      { text: '1600', correct: false },
      { text: '1566', correct: false }
    ]
  },
  {
    question: 'Is web development fun?',
    answers: [
      { text: 'Kinda', correct: false },
      { text: 'YES!!!', correct: true },
      { text: 'Um no', correct: false },
      { text: 'IDK', correct: false }
    ]
  },
  {
    question: 'What is 4 * 2?',
    answers: [
      { text: '6', correct: false },
      { text: '8', correct: true }
    ]
  },
]

function getRandomNumberBetween(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

const GetRandomQuestionsArray = (howManyQuestions) => {
  const questionsArrayCopy = [...myQuestions];
  const finalQuestionArray = [];

  for (let i = 0; i < howManyQuestions; i++) {
      const randomIndex = getRandomNumberBetween(0, questionsArrayCopy.length);

      const randomQuestion = questionsArrayCopy.splice(randomIndex,1);
      finalQuestionArray.push(randomQuestion[0]);
  }
  return finalQuestionArray;
}
const questions = GetRandomQuestionsArray(3);
console.log(questions)

However as I said in my comment, an easier solution is often to just shuffle the initial array randomly, and then take however many items you want from it:

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
var questions = ["question1","question2","question3","question4","question5"];

var shuffled = shuffle(questions);

console.log(shuffled[0],shuffled[1],shuffled[2]);

Upvotes: 2

klugjo
klugjo

Reputation: 20885

Use a while loop and inside, only add the question to your final array if it's not already present.

Use the find method to check if the question already exists.

There is no need to duplicate your array

const myQuestions = [
  {
    question: 'What is 37 x 89?',
    answers: [
      { text: '6989', correct: false },
      { text: '3293', correct: true },
      { text: '2400', correct: false },
      { text: '9870', correct: false }
    ]
  },
  {
    question: 'What year is the great fire of london?',
    answers: [
      { text: '1666', correct: true },
      { text: '1888', correct: false },
      { text: '1600', correct: false },
      { text: '1566', correct: false }
    ]
  },
  {
    question: 'Is web development fun?',
    answers: [
      { text: 'Kinda', correct: false },
      { text: 'YES!!!', correct: true },
      { text: 'Um no', correct: false },
      { text: 'IDK', correct: false }
    ]
  },
  {
    question: 'What is 4 * 2?',
    answers: [
      { text: '6', correct: false },
      { text: '8', correct: true }
    ]
  },
]

function getRandomNumberBetween(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

const getRandomQuestionFromArray = (array) => {
   const randomIndex = getRandomNumberBetween(0, array.length - 1);
   return array[randomIndex];
}

const getRandomQuestionsArray = (howManyQuestions) => {
  const finalQuestionArray = [];

  // Continue until number of questions requested is reached
  while (finalQuestionArray.length < howManyQuestions) {
      const randomQuestion = getRandomQuestionFromArray(myQuestions);
      
      // check if the random question is already present in the final result
      if (!finalQuestionArray.find(q => q.question === randomQuestion.question)) {
        finalQuestionArray.push(randomQuestion);
      }
  }
  return finalQuestionArray;
}

const questions = getRandomQuestionsArray(3);
console.log(questions);

Upvotes: 1

Yoel
Yoel

Reputation: 7985

Use the filter method in an array

const result = myQuestions.filter(el => el.question !=='What is 4 * 2?');

console.log(result)

Upvotes: 1

Yoel
Yoel

Reputation: 7985

use filter mentod in array java script

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

const myQuestions = [
  {
    question: 'What is 37 x 89?',
    answers: [
      { text: '6989', correct: false },
      { text: '3293', correct: true },
      { text: '2400', correct: false },
      { text: '9870', correct: false }
    ]
  },
  {
    question: 'What year is the great fire of london?',
    answers: [
      { text: '1666', correct: true },
      { text: '1888', correct: false },
      { text: '1600', correct: false },
      { text: '1566', correct: false }
    ]
  },
  {
    question: 'Is web development fun?',
    answers: [
      { text: 'Kinda', correct: false },
      { text: 'YES!!!', correct: true },
      { text: 'Um no', correct: false },
      { text: 'IDK', correct: false }
    ]
  },
  {
    question: 'What is 4 * 2?',
    answers: [
      { text: '6', correct: false },
      { text: '8', correct: true }
    ]
  },
]

const result = myQuestions.filter(el => el.question !=='What is 4 * 2?');

console.log(result)

Upvotes: -2

Related Questions