How can I create a random 16 digit number that doesn't previously exist in a list?
Let's say I have the following list:
const nums = [7856328870763265, 0107654389657487];
I need a function to generate random 16 digit numbers but that doesn't create duplicates.
I have the following:
const val = Math.floor(1000 + Math.random() * 9000).toString();
const random16digitnumber = +val+val+val+val;
console.log(random16digitnumber);
console.log(typeof random16digitnumber);
But im afraid at some point it will start creating duplicates. I'm using the random16digitnumber as a primary key in a SQL database for a small school project.
So going back to my example, how can I create a random 16 digit number that doesn't previously exist in an array?
I don't know much about JavaScript but I'm going to give you a general solution.
You need to use a loop statement to loop through the list to check whether the generated number is in the array. If it is not in the array then append/push it to the list. Else regenerate the random number.
Could have written it in php or python
I'll answer with an inline comment. I left your algo "as is". There might be reasons of why you're doing it this way; so I just implemented the logic you've wished for.
const nums = [7856328870763265, 0107654389657487];
const getNextRandomNumber = () => {
const val = Math.floor(1000 + Math.random() * 9000).toString();
const candidate = +val+val+val+val;
// the generated number is part of the list;
// recursively call this function to generate another one
// (this works like a loop, just using call recursion)
// until a number is found that is not part of the list
// then the return below this if() is triggered
// and the "good" candidate is returned
if (nums[candidate]) {
return getNextRandomNumber();
}
// parseInt makes sure the string is converted back to number
// making sure we're using base 10, even if the first digit
// might be 0
return parseInt(candidate, 10);
}
// push() adds an element to the array
// the return value (100% guaranteed to be collision free random number)
// is added via the function call. The function logic makes sure
// it is absolutely unique
nums.push(getNextRandomNumber());
If you want true randomness without duplicates, then you will need to every time check the list to ensure that it's not been included. Eventually that could become a drag on the system, but there's no alternative.
If you want a small enough chance of duplicates appearing that your code can likely ignore it (unless you have phenomenal volume), then GUIDs are probably your best bet... but these are far longer than 16 digits.
However, if you want numbers that appear at a casual glance to be random, although they are far from it, then a simple algorithm will give you all 10^16
numbers in a random-looking order. We can achieve this by taking subsequent numbers as a linear transform of the current ones. We can multiply our current value by some number, a
and add another value, b
, then take the last 16 digits to get the next value. So long as a
and b
have no common proper factors and neither has any common proper factors with 10^16, this process will cycle through all numbers from zero to 9999999999999999
in a seemingly random order.
The easiest way to ensure there are no common factors is just to choose two 16-digit primes, which we can do at a site like https://bigprimes.org/.
If we can keep hold of or easily look up the last-used id, then we can write it like this:
const a = BigInt ( '7791448648907857')
const b = BigInt ( '2320712743817497')
const c = BigInt ('10000000000000000')
const nextId = (previousId) =>
((a * BigInt(previousId) + b) % c)
.toString () .padStart ('0', 16)
const lastRecord = {id: '1234567890123456', more: 'fields'}
console .log (nextId (lastRecord .id))
If we can't easily keep track of the last id, but can keep a sequential counter, say n
, we can always generate it using the formula
id_n = (a ** n + b * ((a ** n - 1) / (a - 1))) % c
That would involve efficiently managing modular exponentiation, but that's a well-solved problem and is easy enough to implement.
Don't forget that this is no only not cryptographically secure, it's far far from random. But it will give you random-looking number without repetitions.