generate random unique 4 digit codes without brute force

Since you have a constrained number of values that will easily fit in memory, the simplest way I know of is to create a list of the possible values and select one randomly, then remove it from the list so it can’t be selected again. This will never have a collision with a previously used number:

function initValues(numValues) {
    const values = new Array(numValues);
    // fill the array with each value
    for (let i = 0; i < values.length; i++) {
        values[i] = i;
    }
    return values;
}

function getValue(array) {
    if (!array.length) {
        throw new Error("array is empty, no more random values");
    }
    const i = Math.floor(Math.random() * array.length);
    const returnVal = array[i];
    array.splice(i, 1);
    return returnVal;
}

// sample code to use it
const rands = initValues(10000);
console.log(getValue(rands));
console.log(getValue(rands));
console.log(getValue(rands));
console.log(getValue(rands));

This works by doing the following:

  1. Generate an array of all possible values.
  2. When you need a value, select one from the array with a random index.
  3. After selecting the value, remove it from the array.
  4. Return the selected value.
  5. Items are never repeated because they are removed from the array when used.
  6. There are no collisions with used values because you’re always just selecting a random value from the remaining unused values.
  7. This relies on the fact that an array of integers is pretty well optimized in Javascript so doing a .splice() on a 10,000 element array is still pretty fast (as it can probably just be memmove instructions).

FYI, this could be made more memory efficient by using a typed array since your numbers can be represented in 16-bit values (instead of the default 64 bits for doubles). But, you’d have to implement your own version of .splice() and keep track of the length yourself since typed arrays don’t have these capabilities built in.

For even larger problems like this where memory usage becomes a problem, I’ve used a BitArray to keep track of previous usage of values.


Here’s a class implementation of the same functionality:

class Randoms {
    constructor(numValues) {
        this.values = new Array(numValues);
        for (let i = 0; i < this.values.length; i++) {
            this.values[i] = i;
        }
    }
    getRandomValue() {
        if (!this.values.length) {
            throw new Error("no more random values");
        }
        const i = Math.floor(Math.random() * this.values.length);
        const returnVal = this.values[i];
        this.values.splice(i, 1);
        return returnVal;
    }
}

const rands = new Randoms(10000);
console.log(rands.getRandomValue());
console.log(rands.getRandomValue());
console.log(rands.getRandomValue());
console.log(rands.getRandomValue());

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top