Generate a random 4 digit number with no repeating digits - javascript

I have this function to create a random 4 digit number:
generateCode = function(){
var fullNumber = [];
var digit1 = Math.floor(Math.random() * 9) + 1;
var digit2 = Math.floor(Math.random() * 9) + 1;
var digit3 = Math.floor(Math.random() * 9) + 1;
var digit4 = Math.floor(Math.random() * 9) + 1;
fullNumber.push(digit1, digit2, digit3, digit4);
this.theCode(fullNumber.join("")) ;
}
But I need to create a 4 digit random number with no repeating digits.
So "1234" or "9673". But not "1145" or "5668"
Is there an efficient way to do this?

You can use this handy shuffle function to shuffle an array containing the numbers, and pick the first 4.
function random4Digit(){
return shuffle( "0123456789".split('') ).join('').substring(0,4);
}
function shuffle(o){
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
alert( random4Digit() );
Edit: If you actually want a Number not starting with 0:
function random4DigitNumberNotStartingWithZero(){
// I did not include the zero, for the first digit
var digits = "123456789".split(''),
first = shuffle(digits).pop();
// Add "0" to the array
digits.push('0');
return parseInt( first + shuffle(digits).join('').substring(0,3), 10);
}
function shuffle(o){
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
alert( random4DigitNumberNotStartingWithZero() );

Create an array of numbers, randomize it, then slice out the first 4 and join them together.
var numbers = [0,1,2,3,4,5,6,7,8,9];
function shuffleArray(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;
}
shuffleArray(numbers).slice(0,4).join('');

It really depends on how you'd like to approach the problem. One solution is to store the digits you've used already in an array, then search the array when you generate a number. If the generated number is contained in the array, then you try generating another number. Doing a few different steps like this is also easier to follow if you have a few different functions. See my included example below:
var checkRandomUsed = function(array, number){
return array.indexOf(number) > -1;
}
var getCheckedRandom = function(array){
var random = getRandomNum();
while (checkRandomUsed(array, random)){
random = getRandomNum();
}
return random;
}
var getRandomNum = function(){
return Math.floor(Math.random() * 9) + 1;
}
var generateCode = function(){
var usedNumbers = [];
for (var i = 0; i < 4; i++){
usedNumbers.push(getCheckedRandom(usedNumbers));
}
return usedNumbers.join("");
}

As an update, try this...
const value = (new Array(4))
.map(() => (Math.floor(Math.random() * 9) + 1).toString()).reduce((p, c) => p + c);

This will do it if you're ok with potentially having 0 as the first digit:
var getNum = () => randoSequence(0, 9).slice(-4).join("");
console.log(getNum());
<script src="https://randojs.com/1.0.0.js"></script>
This will do it without 0 as the first digit:
function getNum(){
var sequenece = randoSequence(0, 9).slice(-4);
return (sequenece[6] ? sequenece.slice(-4) : sequenece.slice(0, 4)).join("");
}
console.log(getNum());
<script src="https://randojs.com/1.0.0.js"></script>
Both of these codes use rando.js to simplify the randomness and make it more readable, so don't forget to add the script tag to the head of your HTML document if you want to use either of them.

Related

How to use math.random again to get a different value if the values are the same in javascript

I am trying to get a different value from the previous value of math.random, so when the numbers are written to the document, if they are the same then math.random will generate another number that is not the same. It may need to keep generating until the value is different.
function rands() {
return Math.floor(Math.random() * 20) + 1;
}
var rand1 = rands();
var rand2 = rands();
var rand3 = rands();
var rand4 = rands();
var rand = [];
function myFunction() {
document.getElementById("random1").value = rand1;
document.getElementById("random2").value = rand2;
document.getElementById("random3").value = rand3;
document.getElementById("random4").value = rand4;
if(rand1 == rand2 || rand1==rand3 || rand1==rand4 || rand2 == rand3 || rand2 == rand4 || rand3==rand4){
console.log("Duplicate");
}
}
myFunction()
You could rewrite your rands function to look for values which have already been used:
function rands(used) {
let r;
do {
r = Math.floor(Math.random() * 20) + 1;
} while (used.indexOf(r) >= 0);
return r;
}
var rand = [];
for (let i = 0; i < 4; i++) rand[i] = rands(rand);
If you want to guarantee uniqueness you can splice random indexes from an array. This will save the effort of repeatedly calling the function when you have clashes:
function rand_maker(length) {
let arr = Array.from({length: length}, (_, i) => i+1)
return () => {
let index = Math.floor(Math.random() * arr.length)
return arr.splice(index, 1)[0];
}
}
let rands = rand_maker(20)
console.log(rands())
console.log(rands())
console.log(rands())
console.log(rands())
Once you can no longer make random numbers in the range, it will returned undefined.

Java script random number with allowed to 2 repeat value

How to create the random number to assign in java script array with following condition.
need to create random number with (1-28).
Number allowed to repeat 2 times. (EX: 1,3,5,4,5). .
Simple solution for adding a number to an array based on your criteria:
function addNumberToArray(arr){
const minValue = 1;
const maxValue = 28;
if(arr.length==maxValue*2){ //no possible numbers left
return;
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function isValueInArrayLessThenTwoTimes(value, arr){
var occurrences = 0;
for(var i=0; i<arr.length; i++){
if(arr[i]===value){
occurrences++;
}
}
return occurrences<2;
}
var newValue;
do {
newValue = getRandomArbitrary(minValue,maxValue);
} while(!isValueInArrayLessThenTwoTimes(newValue, arr));
arr.push(newValue);
}
A shorter and faster solution:
min=1;
max=28;
nums= new Array();
for(i=1;nums.length<28;i++){
a = Math.round(Math.random()*(max-min+1)+min);
if(nums.indexOf(a)==-1 || nums.indexOf(a)==nums.length-nums.reverse().indexOf(a)-1){
if(nums.indexOf(a)>-1){
nums.reverse();
}
nums.push(a);
}
}
console.log(nums);
https://jsfiddle.net/znge41fn/1/
var array = [];
for (var i = 0; i < 28; i++) {
var randomNumberBetween1and28 = Math.floor(Math.random() * (28 - 1) + 1);
while (getCount(array, randomNumberBetween1and28) > 2) {
randomNumberBetween1and28 = Math.floor(Math.random() * (28 - 1) + 1);
}
array.push(randomNumberBetween1and28);
}
function getCount(arr, value) {
var count = 1;
for (var i = 0; i < arr.length; i++) {
if (value == arr[i]) count++;
}
return count;
}

Generating alphanumerical sequence javascript

I have written a terribly slow function for generating codes that go from AA000 to ZZ999 (in sequence not random). And I have concluded that there has to be a better way to do this. Any suggestions on how to make this faster?
function generateAlphaNumeric(){
theAlphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
resultArrray = [];
resultArrray2 = [];
teller = 0;
for(i in theAlphabet){
for(x in theAlphabet){
resultArrray[teller] = theAlphabet[i] + theAlphabet[x];
teller++;
}
}
teller = 0;
for(x = 0; x<10; x++){
for(y = 0; y<10; y++){
for(z = 0; z<10; z++){
resultArrray2[teller] = x.toString() + y.toString() +z.toString();
teller++;
}
}
}
teller = 0;
finalArray = [];
for(index in resultArrray){
for(i in resultArrray2){
finalArray[teller] = resultArrray[index] + resultArrray2[i];
teller++;
}
}
//console.log(resultArrray);
//console.log(resultArrray2);
console.log(finalArray);
}
This should be considerably faster:
var theAlphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z'];
var theDigits = ['0','1','2','3','4','5','6','7','8','9'];
var result = [];
for (var i=0 ; i<26 ; i++) {
var prefix1 = theAlphabet[i];
for (var j=0 ; j<26; j++) {
var prefix2 = prefix1 + theAlphabet[j];
for(var x = 0; x<10; x++){
var prefix3 = prefix2 + theDigits[x];
for(var y = 0; y<10; y++){
var prefix4 = prefix3 + theDigits[y];
for(var z = 0; z<10; z++){
result.push(prefix4 + theDigits[z]);
}
}
}
}
}
Key ideas:
Generate everything in one run
Reuse partial strings as much as possible
However, I don't see how such an exhaustive list is useful. There are exactly 26 * 26 * 1000 different codes. So instead of maintaining an array with all codes it could make sense to simply build a function that generates the specific code requested:
function getCode(number) {
var z = number % 10;
number -= z; number /= 10;
var y = number % 10;
number -= y; number /= 10;
var x = number % 10;
number -= x; number /= 10;
var a = number % 26;
number -= a; number /= 26;
var b = number;
return theAlphabet[a] + theAlphabet[b] + theDigits[x] + theDigits[y] + theDigits[z];
}
function generate() {
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
array = [];
for (var i = 0; i < str.length; i++) {
for (var j = 0; j < str.length; j++) {
for (var k = 0; k < 10; k++) {
for (var l = 0; l < 10; l++) {
for (var m = 0; m < 10; m++) {
ar.push(str[i] + str[j] + k + l + m);
}
}
}
}
}
return array;
}
console.log(generate());
This will generate a array of all the codes .. U can save that array and parse it easily using a loop.
Try this solution:
function generate() {
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
ar = [];
for (var index1 = 0; index1 < str.length; index1++) {
for (var index2 = 0; index2 < str.length; index2++) {
for (var index3 = 0; index3 < 1000; index3++) {
ar.push(str[index1] + str[index2] + ('000' + index3).slice(-3));
}
}
}
return ar;
}
console.log(generate());
I didn't test it, but it should do the trick
function generateAlphaNumeric()
{
var theAlphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
var result = [];
// Will take a random letter inside theAlphabet
// Math.floor(Math.random() * theAlphabet.length) will generate a random number between 0 and 25
var i = 0;
while(i<2)
{
var letter = theAlphabet[Math.floor(Math.random() * theAlphabet.length)];
result.push(letter);
i++;
}
i = 0;
while(i<3)
{
// Adds a random number between 0 and 9
result.push(Math.floor(Math.random() * 10));
i++;
}
return result;
}
From a computational complexity perspective, unfortunately this is the best you can do. From a sheer number of instructions perspective, you can do a bit better (as others have pointed out), but it's still going to be the same order of complexity (remember that constants / multipliers are irrelevant in big-O complexity). You can also optimize the storage a bit.
Think about it. Your array needs to have 26 * 26 * 10 * 10 * 10 members. This means you need to at least touch that many elements.
Let N = number of elements in the alphabet
Let M = number of elements in your digit queue
Best Case Order Complexity = O(N * N * M * M * M) (if all you had to do was assign values)
Best case storage complexity = same as above (you have to store all the codes)
Right now you are using the following operations:
for(i in theAlphabet){ // *O(N)*
for(x in theAlphabet){ // *O(N)*
resultArrray[teller] = theAlphabet[i] + theAlphabet[x];// *(O(1))*
}
}
for(x = 0; x<10; x++){ // O(M)
for(y = 0; y<10; y++){ // O(M)
for(z = 0; z<10; z++){ // O(M)
resultArrray2[teller] = x.toString() + y.toString() +z.toString(); // O(1) (technically this is O(length of x + y + z)
teller++;
}
}
}
for(index in resultArrray){ // O(N * N)
for(i in resultArrray2){ // O(M * M * M(
finalArray[teller] = resultArrray[index] + resultArrray2[i]; //O(1)
teller++;
}
}
So at the end of the day your order complexity is O(N * N * M * M * M), which is the best you can do.
The bigger question is why you want to generate all the codes at all. If all you want is to create a unique code per order number or something, you can make a state machine like:
function getNextCode(previousCode) {
// in here, just increment the previous code
}
If all you want is a random identifier, consider using a hash of the timestamp + something about the request instead.
If you don't care about uniqueness, you can always just generate a random code.
All of the above are O(1).

Shuffle array and prevent more than 2 in a row

I have an array being built like this:
var entries = ['L','L','L','L','L','L','L','L','L','L','R','R','R','R','R','R','R','R','R','R','M','M','M','M','M']
This means the array is always filled with 10 times L, 10 times R and 5 times M
The output I want to achieve is a randomly generated array, so I came up with the simple solution to just shuffle it with
function shuffle(o){
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
The problem I have now is that there is a rule for the outcome, never have one of these letters more than 2 times in a row. So I thought I just use a do/while loop to shuffle until that criteria is met. But in my test runs this totally fails with long loops.
So my question is - what is the best way to build this array without depending on luck. My full program that fails is something like this
function shuffle(o){
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
function createProgram(numShooters){
var programs = [];
for(var s = 0; s < numShooters; s++){
//Build array with L/R/M
for( d=0; d < 10; d++ ){
program.push('L');
program.push('R');
if(d < 5){
program.push('M');
}
}
// This will run way too long and is not reliable
//do{
// program = shuffle(program);
//}while(!checkProgram(program))
if(!checkProgram(program)){
console.log('invalid program at ' + s);
}
programs[s] = program;
}
return programs;
}
function checkProgram(program){
var len = program.length;
var last = null;
var dups = 0;
for(var i=0; i<len; len++){
if(program[i] == last){
dups++;
}else{
dups = 0;
}
if(dups == 2){
return false;
}
last = program[i];
}
return true;
}
createProgram(5);
Instead of just shuffle arrays and hope for one without duplicates, you can create them by picking characters by random and specifically avoid to pick the character that was picked previously.
If you keep track of how many there are left to pick of each character, you can control the odds for the character to pick so that the distribution is correct. If for example the first two characters are L, then there are 10 R and 5 M left to pick from (and 8 L, but they are excluded for the next pick), so there should be a 2 in 3 chance to pick an R and a 1 in 3 chance to pick and M.
This approach can run into a dead end, where the array can't be completed, so it has to start over. Running it a few hundred times I have seen something like a 10% overhead, so if you create five arrays you should by average see a retry every other time.
function createProgram(numShooters){
var programs = [];
for(var s = 0; s < numShooters; s++){
var chars = [ 'L', 'R', 'M' ];
var program;
do {
program = [];
var cnt = [ 10, 10, 5, 0 ]; // picks left
var prev = 3; // previous pick
var tot = 25; // total picks left
while (program.length < 25) {
// check for duplicates
var x = program.length >= 2 && program[program.length - 2] == program[program.length - 1] ? prev : 3;
// check if more picks are possible
if (tot - cnt[x] <= 0) {
console.log('invalid program ' + program);
break;
}
// pick from the possible
var r = Math.floor(Math.random() * (tot - cnt[x]));
// determine what character was picked
var c = 0;
while (c == x || r >= cnt[c]) {
if (c != x) r -= cnt[c];
c++;
}
program.push(chars[c]);
cnt[c]--;
tot--;
prev = c;
}
} while (program.length < 25);
programs[s] = program;
}
return programs;
}
console.log(createProgram(1).toString());
So this is the final solution I came up with, as commented Guffas solution also works nice and smooth. But after doing some tests mine is about 30% faster and more readable, but way longer so I'll accept Guffas - thanks to everybody for their input!
function createProgram(numShooters){
var programs = [];
for(var s = 0; s < numShooters; s++){
var program = buildProgram();
programs[s] = program;
}
return programs;
}
function buildProgram(){
var program = [];
var ls = fillArray('L',10);
var rs = fillArray('R',10);
var ms = fillArray('M',5);
//Use either L or R to mix into M - adds variation
var side = Math.random() > 0.5 ? ls : rs;
var otherSide = side == ls ? rs : ls;
var initProg = side.concat(ms);
initProg = shuffle(initProg);
var program = [];
//Correcting invalid positions as suggested
for(var p1 = 0; p1 < initProg.length; p1++){
if(p1 > 1 && initProg[p1-1] == initProg[p1-2] && initProg[p1-1] == initProg[p1]){
if(otherSide.length > 0){
program.push(otherSide.pop());
}else{
return buildProgram(); //impossible state, redo...
}
}
program.push(initProg[p1]);
}
//Fill into remaining other pos
for(var p2 = 0; p2 < otherSide.length; p2++){
program = addAtRandomPos(program,otherSide[p2]);
}
return program;
}
function addAtRandomPos(arr,chr){
var pos = getRandomInt( 0, arr.length - 1 );
var charCur = arr[pos];
var pprev = pos > 1 ? arr[pos-2] : null;
var prev = pos > 0 ? arr[pos-1] : null;
var next = pos < arr.length - 1 ? arr[pos] : null;
var nnext = pos < arr.length - 2 ? arr[pos+1] : null;
var str = pprev + prev + chr + next + nnext;
if(str.indexOf('MMM') !== -1 || str.indexOf('RRR') !== -1 || str.indexOf('LLL') !== -1){
return addAtRandomPos(arr,chr);
}else{
arr.splice(pos,0,chr);
}
return arr;
}
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function fillArray(chr,num){
var arr = [];
for(i = 0; i < num; i++){
arr.push(chr);
}
return arr;
}

Generating unique 6 digit code js

I am trying to generate 6 digit code using JS.
it must contains 3 digits and 3 chars.
here is my code
var numbers = "0123456789";
var chars = "acdefhiklmnoqrstuvwxyz";
var string_length = 3;
var randomstring = '';
var randomstring2 = '';
for (var x = 0; x < string_length; x++) {
var letterOrNumber = Math.floor(Math.random() * 2);
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
for (var y = 0; y < string_length; y++) {
var letterOrNumber2 = Math.floor(Math.random() * 2);
var rnum2 = Math.floor(Math.random() * numbers.length);
randomstring2 += numbers.substring(rnum2, rnum2 + 1);
}
var code = randomstring + randomstring2;
the code result will be 3chars + 3 numbers .. I want to just rearrange this value to be random value contains the same 3 chars and 3 numbers
http://jsfiddle.net/pgDFQ/101/
You could shuffle your current codes with a function like this (from this answer)
//+ Jonas Raoni Soares Silva
//# http://jsfromhell.com/array/shuffle [v1.0]
function shuffle(o){ //v1.0
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
You could use it like this:
alert(shuffle("StackOverflow".split('')).join(''));
Here is an updated demo with this code.
Here is the code for you
function(count){
var chars = 'acdefhiklmnoqrstuvwxyz0123456789'.split('');
var result = '';
for(var i=0; i<count; i++){
var x = Math.floor(Math.random() * chars.length);
result += chars[x];
}
return result;
}
what you can do is use a dingle loop from 6 times and use random character and random number function one by one while also incrementing by 1, Although not that a good option but this may also offer some flexibility
Try this:
var numbers = "0123456789";
var chars= "acdefhiklmnoqrstuvwxyz";
var code_length = 6;
var didget_count = 3;
var letter_count = 3;
var code = '';
for(var i=0; i < code_length; i++) {
var letterOrNumber = Math.floor(Math.random() * 2);
if((letterOrNumber == 0 || number_count == 0) && letter_count > 0) {
letter_count--;
var rnum = Math.floor(Math.random() * chars.length);
code += chars[rnum];
}
else {
number_count--;
var rnum2 = Math.floor(Math.random() * numbers.length);
code += numbers[rnum2];
}
}
I might note that such a code should not be considered truly random as the underlying functions could be predictable depending on the javascipt engine running underneath.

Categories

Resources