skip to Main Content

I have an array of fruits. I want to fill an array of size 12 with fruits such that every fruit in the new array has even number of occurrences.

const fruitsList = [
  { id: 1, img: "/apple.jpg", flipped: false },
  { id: 2, img: "/banana.jpg", flipped: false },
  { id: 3, img: "/cherry.jpg", flipped: false },
  { id: 4, img: "/coconut.jpg", flipped: false },
  { id: 5, img: "/grapes.jpg", flipped: false },
  { id: 6, img: "/lemon.jpg", flipped: false },
  { id: 7, img: "/muskmelon.jpg", flipped: false },
  { id: 8, img: "/watermelon.jpg", flipped: false },
];

let randomOrderedFruits = [];

const generateRandomFruits = () => {
  const arrLength = Object.keys(randomOrderedFruits).length;
  if (arrLength === 12) return;
  const randomIndexOfFruit = Math.floor(Math.random() * 8);
  let timesToRepeat = Math.floor(Math.random() * 4);
  timesToRepeat = timesToRepeat % 2 === 0 ? timesToRepeat : timesToRepeat + 1;
  fillWithRandom(timesToRepeat, randomIndexOfFruit);

  generateRandomFruits();
};
const usedIndices = {};

const fillWithRandom = (timesToRepeat, randomIndexOfFruit) => {
  if (timesToRepeat === 0 || randomOrderedFruits.length === 12) return;
  //repeat selected randomIndexOfFruit such that it occurs 2 or 4 times.
  for (let i = 0; i < timesToRepeat; i++) {
    const randomIndexToInsertAt = Math.floor(Math.random() * 12);
    if (usedIndices[randomIndexToInsertAt]) {
      fillWithRandom(timesToRepeat, randomIndexOfFruit);
    } else {
      usedIndices[randomIndexToInsertAt] = true;
      randomOrderedFruits[randomIndexToInsertAt] = fruitsList[randomIndexOfFruit];
    }
  }
};

const randomizedFruits = generateRandomFruits();

console.log(randomizedFruits)

What I’m doing above is select a random index of fruitsList.

Again generate a random number to determine how many times the selected random index must be in new array(either 2 or 4 times).

Then selecting a random index of new array at which the fruit must be inserted.

My code gives max call stack exceeded since some of the indices to be filled never occur in randomIndexToInsertAt. The numbers in usedIndices are repeated.

Full code is atlink

2

Answers


  1. Might not be your core problem, but the following

    const arrLength = Object.keys(randomOrderedFruits).length;
    

    should be

    const arrLength = randomOrderedFruits.length;
    

    since it is an array, not a key/value object.

    Login or Signup to reply.
  2. The problem is that you have an infinite recursive "loop", as generateRandomFruits calls generateRandomFruits again and again and again.

    Secondly you used a retry-system with recursion where you tell it to assign a fruit timesToRepeat times. But this ignores that you might already have successfully assigned one (or more) fruits. And so you end up in a situation where you overshoot the number of fruits to assign and will reach 12 earlier than expected.

    Although you could fix all this, it is better is to avoid that you have to retry. Instead of randomly choosing a target index, just push the selections to the target array, and then shuffle it.

    As you need to make sure to have an even number of selections of the selected fruits, you could select only 6 random fruits (each time from the whole list of fruits), and then add them to your result twice. This way you ensure that you have an even number of each selected fruit.

    Finally shuffle the result array to have a random distribution. For this you can use one of the popular solutions from How to randomize (shuffle) a JavaScript array?.

    In the below snippet I used a simplified fruits-array, as the object structure of the fruits is not relevant for this problem. So here they are just letters:

    function shuffle(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[j], array[i]] = [array[i], array[j]]
        }
    }
    
    // Simplified fruits list (the structure of the elements is not relevant) 
    const fruitsList = [
      "A", "B", "C", "D", "E", "F", "G", "H"
    ];
    
    const randomOrderedFruits = [];
    // Make 6 random selection and double each of them:
    for (let i = 0; i < 6; i++) {
        const randomIndexOfFruit = Math.floor(Math.random() * fruitsList.length);
        const fruit = fruitsList[randomIndexOfFruit];
        randomOrderedFruits.push(fruit, fruit);
    }
    // ... and then shuffle:
    shuffle(randomOrderedFruits);
    
    console.log(randomOrderedFruits);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search