How to Randomly Choose an Element from an Array that Wasn't Chosen before in JavaScript? - Stack Overflow

I want to run a function that each time randomly chooses an element from an array that wasn't chos

I want to run a function that each time randomly chooses an element from an array that wasn't chosen before. And if all elements were chosen, I want to reset the used elements and start from the beginning.

Hope this makes sense.

I already have a function that chooses a random element from an array. But I also don't want it to choose elements that were chosen before unless all elements were already chosen.

Here is what I have got so far (credit to @Kelly):

var item = items[Math.floor(Math.random() * items.length)]

I want to run a function that each time randomly chooses an element from an array that wasn't chosen before. And if all elements were chosen, I want to reset the used elements and start from the beginning.

Hope this makes sense.

I already have a function that chooses a random element from an array. But I also don't want it to choose elements that were chosen before unless all elements were already chosen.

Here is what I have got so far (credit to @Kelly):

var item = items[Math.floor(Math.random() * items.length)]
Share Improve this question asked Mar 23, 2020 at 10:45 Anatol ZakrividorogaAnatol Zakrividoroga 4,5482 gold badges32 silver badges57 bronze badges 12
  • 2 The easiest is to shuffle the array -> keep an index of the current element -> increment it every time you get the "next random". On pletion, just wrap around. – VLAZ Commented Mar 23, 2020 at 10:46
  • @VLAZ do you mind giving an example with code? – Anatol Zakrividoroga Commented Mar 23, 2020 at 10:48
  • @VLAZ just imagine if your random number es as 3 5 times, this will have to be increment again and again and build logic for that – Rajesh Commented Mar 23, 2020 at 10:49
  • @Rajesh why would you be generating random numbers, after you've shuffled the array? – VLAZ Commented Mar 23, 2020 at 10:55
  • 1 @Rajesh again, non-issue after shuffling the array. It's already random order, no need to fetch random item from it, you can progress linearly. – VLAZ Commented Mar 23, 2020 at 11:06
 |  Show 7 more ments

4 Answers 4

Reset to default 3

You can try something like this:

Idea

  • Create a utility function that takes an array and returns you a random value.
  • Inside this Array, maintain 2 array, choices and data.
  • In every iteration, remove 1 item from data and put it in chosenItems
  • Once the length of data reaches 0, set chosenItems or originalArray as data and repeat process.

Benefit of this approach would be,

  • You dont need to maintain and pass array variable.
  • It can be made generic and used multiple times.

function randomize(arr) {
  let data = [...arr];
  let chosenItems = [];

  function getRandomValue() {
    if (data.length === 0) {
      data = chosenItems;
      chosenItems = [];
    }
    const index = Math.floor(Math.random() * data.length);
    const choice = data.splice(index, 1)[0];

    chosenItems.push(choice);
    return choice;
  }
  
  return {
    randomItem: getRandomValue
  }
}

const dummyData = [ 1,2,3,4,5 ];

const randomizeData = randomize(dummyData);

for (let i = 0; i< 10; i++) {
  console.log(randomizeData.randomItem())
}

The easiest way to handle this is:

  • Shuffle the array (also link here). I've taken the implementation directly from this answer and removed the ments for brevity.
  • Maintain an index for the current item.
  • When getting the next item, fetch the index and increment to the next one.
  • Once you finish with the array, return the index to the start and re-shuffle the array.

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

  while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}


var items = ["alpha", "beta", "gamma", "delta", "epsilon"];
var index = Infinity;

function start() {
  console.log("----- shuffling -----")
  shuffle(items);
  index = 0;
}

function nextItem() {
  if (index >= items.length) {
    //re-start
    start()
  }
  
  //return current index and increment
  return items[index++];
}

document.getElementById("click_me")
  .addEventListener("click", function() {
    console.log(nextItem())
  })
<button id="click_me">Next random</button>

This can also be converted to a generator function

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

  while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

function* random(array) {
  let index = Infinity;
  const items = array.slice(); //take a copy of the array;
  
  while(true) {
    if (index >= array.length) {
      console.log("----- shuffling -----")
      shuffle(items);
      index = 0;
    }
    
    yield items[index++];
  }
}


var items = ["alpha", "beta", "gamma", "delta", "epsilon"];

//start the generator
const generateRandom = random(items);

document.getElementById("click_me")
  .addEventListener("click", function() {
    console.log(generateRandom.next().value)
  })
<button id="click_me">Next random</button>

One possible way is prime walk.

First have the list of e.g. 500 items. Get the next prime number that is greater than 500. Here 503. Select random seed. This seed is any number that is constant for an user.

var prime = 503;
var list = ["item1", "item2", ... "item500"];

function pick_nth(seed, n, p, l) {
    if(!n) return l[seed % p];
    return pick_nth((seed + l.length) % p, n - 1, l);
}

Picking up n:th item from list is easy. For example:

pick_nth(seed, 0, prime, list);  // first item
pick_nth(seed, 1, prime, list);  // second item
...
pick_nth(seed, 499, prime, list);  // 500th item

The order of the items returned are permutated by the seed.

Here's a solution that's pretty short. It uses randojs. to simplify the randomness and make it more readable, though I kinda threw a wrench in the "easy to read" part by making it super short. If you're having trouble understanding, here are some resources that will help explain: declaring variables on one line, the ternary operator, different ways to declare a function, the pop() method, and randojs

You can actually make the JavaScript one line if you want by just removing the line break, but I chose to make it two for the sake of clarity and shorter lines.

var arr = ["one", "two", "three", "four"], shuffled = randoSequence(arr), 
uniqueRandom = () => (shuffled.length ? shuffled : shuffled = randoSequence(arr)).pop().value;
<script src="https://randojs./1.0.0.js"></script>
<button onclick="console.log(uniqueRandom());">Log a unique random</button>

NOTE: this code won't work if you forget to import randojs with the script tag, so make sure to paste that in the head of your HTML document if you want to use this code.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745151283a4613881.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信