Reduce the likelihood of getting a random item from the array in the same way as the previous one

Let's say I have an array like

var arr = [1,2,3,4,5,6,7,8,9,10,11,12];

      

and I want to get a random element of the array, but later I would like to re-randomize my current element. What is an efficient way to eliminate or reduce the likelihood of getting the same item again?

Does this help like this:

current != arr[Math.floor(Math.random() * 12)] ? current = arr[Math.floor(Math.random() * 12)] : arr[Math.floor(Math.random() * 12)];

      

I mean, will it recalculate a random array index every time, or will it just refer to a single value? What's better?

+3


source to share


7 replies


If you can keep the array unsorted: (if not, you can use an array that only contains the indices of the elements in the first array)

var array = [ ... ];
var len = array.length;

function getRandomItem(){
    if (len <= 0) len = array.length;
    var item = Math.floor(Math.random()*len--);
    var x = array[item];
    array[item] = array[len];
    array[len] = x;
    return array[len];
}

      

The idea is to exclude already submitted items by placing them outside of the selection range. The function getRandomItem()

will not return the same element twice until all other elements have been returned.




The next modification will only prevent the function from returning the same item that was returned in the previous call, as requested.

var array = [ 3, 1, 4, 5, 9, 2, 6, 8, 7 ];
var len = array.length-1;

function getRandomItem(){
    if (len == 0) return array[0];
    var item = Math.floor(Math.random()*len);
    var x = array[item];
    array[item] = array[len];
    array[len] = x;
    return array[len];
}

document.write("Starting array: " + array + "<br/>");
document.write("Selected value: " + getRandomItem() + "<br/>");
document.write("Resulting array: " + array);
      

Run code


Also see Fisher-Yates Shuffle

+2


source


I think the best solution is to put a loop while

to check if the value is similar to the previous one or not.

var arr = [1,2,3,4,5,6,7,8,9,10,11,12];

      

Then you write:



   var last_generated_value = null;
   var val = Math.random();
   val = Math.floor(val * 12);

   while(last_generated_val == val)
   {
       val = Math.random();
       val = Math.floor(val * 12);
   }

   last_generated_value = val;

      

Although you can put the above code block in a parent loop or function to generate a concatenated set of values ​​(in your case, a number).

+1


source


There are so many ways to do this. Maybe add weight to each value and consider it when choosing a random number? Then, when you get it, reduce its weight. For example:

var weights = {};
var max = 12;

function initializeWeights() {
    var i;

    for (i = 1; i <= max; ++i) {
        weights[i] = 100;
    }
}

function getPseudoRandom() {
    var possible_values = [], i, j;

    for (i = 1; i <= max; ++i) {
        for (j = 0; j < weights[i]; ++j) {
            possible_values.push(i);
        }
    }

    random_index = Math.floor(Math.random() * possible_values.length) + 1;
    random = possible_values[random_index];
    weights[random] = weights[random] - 10;
    return random;
}

initializeWeights()
alert(getPseudoRandom());

      

Then you just need to figure out what to do when you reach 0. Perhaps you can increase all the weights by 100.

0


source


Try

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];

var clone = arr.slice();

var res = [];

do {
  res.push(clone.splice(Math.random() * clone.length, 1)[0])
} while (clone.length !== 0);

// do stuff with res
document.write(JSON.stringify(res));

document.write(res[Math.floor(Math.random() * res.length)]);

console.log(arr);
      

Run code


0


source


Perhaps this is normal? It seems to work, but maybe I'm missing the details?

            var current = arr[Math.floor(Math.random() * 12)];
            var prev = current;
            do { current = arr[Math.floor(Math.random() * 12)]; }
            while (current == prev);

      

0


source


You can randomly shuffle the array using the Fischer-Yeiss version of the algorithm and then just iterate over it:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12],
    shuffle = function(array) {
        for (var i = array.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    },
    randomisedArray = shuffle(arr),
    nextItem = function(){
      return randomisedArray.pop();
    };

while(randomisedArray.length>0){
   console.log(nextItem());
}
      

Run code


0


source


You can do it with one calculation:

// Just like before...
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
// Initialize first random index
var currentIndex = Math.floor(Math.random() * arr.length);

// And now...
function Next() {
     currentIndex = (Math.floor(Math.random() * (arr.length - 1)) +
       1 + currentIndex) % arr.length;
     return currentIndex;
}

// Or if you want the next value...
function NextValue() {
     return arr[Next()];
}

      

The idea is that you always randomize how many elements to promote with the maximum (length - 1) and use modulo to truncate the index into the valid range.

0


source







All Articles