[javascript] Generating unique random numbers (integers) between 0 and 'x'

I need to generate a set of unique (no duplicate) integers, and between 0 and a given number.

That is:

var limit = 10;
var amount = 3;

How can I use Javascript to generate 3 unique numbers between 1 and 10?

This question is related to javascript random

The answer is


Use the basic Math methods:

  • Math.random() returns a random number between 0 and 1 (including 0, excluding 1).
  • Multiply this number by the highest desired number (e.g. 10)
  • Round this number downward to its nearest integer

    Math.floor(Math.random()*10) + 1
    

Example:

//Example, including customisable intervals [lower_bound, upper_bound)
var limit = 10,
    amount = 3,
    lower_bound = 1,
    upper_bound = 10,
    unique_random_numbers = [];

if (amount > limit) limit = amount; //Infinite loop if you want more unique
                                    //Natural numbers than exist in a
                                    // given range
while (unique_random_numbers.length < limit) {
    var random_number = Math.floor(Math.random()*(upper_bound - lower_bound) + lower_bound);
    if (unique_random_numbers.indexOf(random_number) == -1) { 
        // Yay! new random number
        unique_random_numbers.push( random_number );
    }
}
// unique_random_numbers is an array containing 3 unique numbers in the given range

const getRandomNo = (min, max) => {
   min = Math.ceil(min);
   max = Math.floor(max);
   return Math.floor(Math.random() * (max - min + 1)) + min; 
}

This function returns a random integer between the specified values. The value is no lower than min (or the next integer greater than min if min isn't an integer) and is less than (but not equal to) max. Example

console.log(`Random no between 0 and 10 ${getRandomNo(0,10)}`)

Just as another possible solution based on ES6 Set ("arr. that can contain unique values only").

Examples of usage:

// Get 4 unique rnd. numbers: from 0 until 4 (inclusive):
getUniqueNumbersInRange(4, 0, 5) //-> [5, 0, 4, 1];

// Get 2 unique rnd. numbers: from -1 until 2 (inclusive):
getUniqueNumbersInRange(2, -1, 2) //-> [1, -1];

// Get 0 unique rnd. numbers (empty result): from -1 until 2 (inclusive):
getUniqueNumbersInRange(0, -1, 2) //-> [];

// Get 7 unique rnd. numbers: from 1 until 7 (inclusive):
getUniqueNumbersInRange(7, 1, 7) //-> [ 3, 1, 6, 2, 7, 5, 4];

The implementation:

function getUniqueNumbersInRange(uniqueNumbersCount, fromInclusive, untilInclusive) {

    // 0/3. Check inputs.
    if (0 > uniqueNumbersCount) throw new Error('The number of unique numbers cannot be negative.');
    if (fromInclusive > untilInclusive) throw new Error('"From" bound "' + fromInclusive
        + '" cannot be greater than "until" bound "' + untilInclusive + '".');
    const rangeLength = untilInclusive - fromInclusive + 1;
    if (uniqueNumbersCount > rangeLength) throw new Error('The length of the range is ' + rangeLength + '=['
        + fromInclusive + '…' + untilInclusive + '] that is smaller than '
        + uniqueNumbersCount + ' (specified count of result numbers).');
    if (uniqueNumbersCount === 0) return [];


    // 1/3. Create a new "Set" – object that stores unique values of any type, whether primitive values or object references.
    // MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
    // Support: Google Chrome 38+(2014.10), Firefox 13+, IE 11+
    const uniqueDigits = new Set();


    // 2/3. Fill with random numbers.        
    while (uniqueNumbersCount > uniqueDigits.size) {
        // Generate and add an random integer in specified range.
        const nextRngNmb = Math.floor(Math.random() * rangeLength) + fromInclusive;
        uniqueDigits.add(nextRngNmb);
    }


    // 3/3. Convert "Set" with unique numbers into an array with "Array.from()".
    // MDN – https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
    // Support: Google Chrome 45+ (2015.09+), Firefox 32+, not IE
    const resArray = Array.from(uniqueDigits);
    return resArray;

}

The benefits of the current implementation:

  1. Have a basic check of input arguments – you will not get an unexpected output when the range is too small, etc.
  2. Support the negative range (not only from 0), e. g. randoms from -1000 to 500, etc.
  3. Expected behavior: the current most popular answer will extend the range (upper bound) on its own if input bounds are too small. An example: get 10000 unique numbers with a specified range from 0 until 10 need to throw an error due to too small range (10-0+1=11 possible unique numbers only). But the current top answer will hiddenly extend the range until 10000.

/**
 * Generates an array with numbers between
 * min and max randomly positioned.
 */
function genArr(min, max, numOfSwaps){
  var size = (max-min) + 1;
  numOfSwaps = numOfSwaps || size;
  var arr = Array.apply(null, Array(size));

  for(var i = 0, j = min; i < size & j <= max; i++, j++) {
    arr[i] = j;
  }

  for(var i = 0; i < numOfSwaps; i++) {
    var idx1 = Math.round(Math.random() * (size - 1));
    var idx2 = Math.round(Math.random() * (size - 1));

    var temp = arr[idx1];
    arr[idx1] = arr[idx2];
    arr[idx2] = temp;
  }

  return arr;
}

/* generating the array and using it to get 3 uniques numbers */
var arr = genArr(1, 10);
for(var i = 0; i < 3; i++) {
  console.log(arr.pop());
}

These answers either don't give unique values, or are so long (one even adding an external library to do such a simple task).

1. generate a random number.
2. if we have this random already then goto 1, else keep it.
3. if we don't have desired quantity of randoms, then goto 1.

_x000D_
_x000D_
function uniqueRandoms(qty, min, max){_x000D_
  var rnd, arr=[];_x000D_
  do { do { rnd=Math.floor(Math.random()*max)+min }_x000D_
      while(arr.includes(rnd))_x000D_
      arr.push(rnd);_x000D_
  } while(arr.length<qty)_x000D_
  return arr;_x000D_
}_x000D_
_x000D_
//generate 5 unique numbers between 1 and 10_x000D_
console.log( uniqueRandoms(5, 1, 10) );
_x000D_
_x000D_
_x000D_

...and a compressed version of the same function:

function uniqueRandoms(qty,min,max){var a=[];do{do{r=Math.floor(Math.random()*max)+min}while(a.includes(r));a.push(r)}while(a.length<qty);return a}


Here’s another algorithm for ensuring the numbers are unique:

  1. generate an array of all the numbers from 0 to x
  2. shuffle the array so the elements are in random order
  3. pick the first n

Compared to the method of generating random numbers until you get a unique one, this method uses more memory, but it has a more stable running time – the results are guaranteed to be found in finite time. This method works better if the upper limit is relatively low or if the amount to take is relatively high.

My answer uses the Lodash library for simplicity, but you could also implement the algorithm described above without that library.

// assuming _ is the Lodash library

// generates `amount` numbers from 0 to `upperLimit` inclusive
function uniqueRandomInts(upperLimit, amount) {
    var possibleNumbers = _.range(upperLimit + 1);
    var shuffled = _.shuffle(possibleNumbers);
    return shuffled.slice(0, amount);
}

Something like this

var limit = 10;
var amount = 3;
var nums = new Array();

for(int i = 0; i < amount; i++)
{
    var add = true;
    var n = Math.round(Math.random()*limit + 1;
    for(int j = 0; j < limit.length; j++)
    {
        if(nums[j] == n)
        {
            add = false;
        }
    }
    if(add)
    {
        nums.push(n)
    }
    else
    {
        i--;
    }
}

for(i = 0;i <amount; i++)
{
    var randomnumber=Math.floor(Math.random()*limit)+1
    document.write(randomnumber)
}

function generateRange(pCount, pMin, pMax) {
    min = pMin < pMax ? pMin : pMax;
    max = pMax > pMin ? pMax : pMin;
    var resultArr = [], randNumber;
    while ( pCount > 0) {
        randNumber = Math.round(min + Math.random() * (max - min));
        if (resultArr.indexOf(randNumber) == -1) {
            resultArr.push(randNumber);
            pCount--;
        }
    }
    return resultArr;
}

Depending on range needed the method of returning the integer can be changed to: ceil (a,b], round [a,b], floor [a,b), for (a,b) is matter of adding 1 to min with floor.


Math.floor(Math.random() * (limit+1))

Math.random() generates a floating point number between 0 and 1, Math.floor() rounds it down to an integer.

By multiplying it by a number, you effectively make the range 0..number-1. If you wish to generate it in range from num1 to num2, do:

Math.floor(Math.random() * (num2-num1 + 1) + num1)

To generate more numbers, just use a for loop and put results into an array or write them into the document directly.


I think, this is the most human approach (with using break from while loop), I explained it's mechanism in comments.

function generateRandomUniqueNumbersArray (limit) {

    //we need to store these numbers somewhere
    const array = new Array();
    //how many times we added a valid number (for if statement later)
    let counter = 0;

    //we will be generating random numbers until we are satisfied
    while (true) {

        //create that number
        const newRandomNumber = Math.floor(Math.random() * limit);

        //if we do not have this number in our array, we will add it
        if (!array.includes(newRandomNumber)) {
            array.push(newRandomNumber);
            counter++;
        }

        //if we have enought of numbers, we do not need to generate them anymore
        if (counter >= limit) {
            break;
        }
    }

    //now hand over this stuff
    return array;
}

You can of course add different limit (your amount) to the last 'if' statement, if you need less numbers, but be sure, that it is less or equal to the limit of numbers itself - otherwise it will be infinite loop.


var randomNums = function(amount, limit) {
var result = [],
    memo = {};

while(result.length < amount) {
    var num = Math.floor((Math.random() * limit) + 1);
    if(!memo[num]) { memo[num] = num; result.push(num); };
}
return result; }

This seems to work, and its constant lookup for duplicates.


Math.floor(Math.random()*limit)+1

Here's a simple, one-line solution:

var limit = 10;
var amount = 3;

randoSequence(1, limit).slice(0, amount);

It uses randojs.com to generate a randomly shuffled array of integers from 1 through 10 and then cuts off everything after the third integer. If you want to use this answer, toss this within the head tag of your HTML document:

<script src="https://randojs.com/1.0.0.js"></script>