Alejandro Reyes
Alejandro Reyes

Reputation: 3

Script Returning Strings of Inconsistent Length

The intention of this script is to print 8 "blocks" of randomly generated alphanumeric values separated by dashes to make a unique ID of 39 characters.

E7L9-XNP4-UB4K-10PU-H8IZ-C69E-3IG2-6P6W

However, I find that this script will sometimes return strings less than 39 characters with blocks that contain only 2 or 3 characters.

21-15-18-5UD1-V471-I158-J23R-M714

I tried putting a condition that would run blockBuilder() recursively if the resulting block was less than 4 characters yet those defective IDs would still be printed to the page.

var alphabet = "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 alphaArray = alphabet.split(",").map(function(l) {
  return l.toUpperCase()
});

function randomLetter() {
  var index = Math.floor(Math.random() * 26);
  return alphaArray[index];
}

function randomNumber() {
  return Math.floor(Math.random() * 10);
}

function blockBuilder() {
  var block = randomChar() + randomChar() + randomChar() + randomChar();

  if (block.length < 4) {
    blockBuilder(); //recursive check
  }

  return block;
}

function idBuilder() {
  return blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder()


}

function randomChar() {
  return Math.floor(Math.random() * 2) == 0 ? randomLetter() : randomNumber();
}

for (var i = 0; i < 100; i++) {
  var v = idBuilder();

  document.write(v + "<br>");

}

What am I missing here? Thanks.

Upvotes: 0

Views: 50

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074385

It's because your randomNumber function returns a number, not a digit. If you have two in a row, they're added together, not concatenated. For instance, in this line:

var block = randomChar() + randomChar() + randomChar() + randomChar();

...suppose the first call returns 2, the second returns 3, the third returns 4, and the fourth returns "X". That's:

var block = 2 + 3 + 4 + "X";

...which is "9X", not "234X". This will happen any time the first and second calls (at least) return numbers.

Converting to string solves it:

function randomNumber() {
  return String(Math.floor(Math.random() * 10));
}

Example:

var alphabet = "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 alphaArray = alphabet.split(",").map(function(l) {
  return l.toUpperCase()
});

function randomLetter() {
  var index = Math.floor(Math.random() * 26);
  return alphaArray[index];
}

function randomNumber() {
  return String(Math.floor(Math.random() * 10));
}

function blockBuilder() {
  var block = randomChar() + randomChar() + randomChar() + randomChar();

  if (block.length < 4) {
    blockBuilder(); //recursive check
  }

  return block;
}

function idBuilder() {
  return blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder()


}

function randomChar() {
  return Math.floor(Math.random() * 2) == 0 ? randomLetter() : randomNumber()
}

for (var i = 0; i < 100; i++) {
  var v = idBuilder();

  document.write(v + "<br>");

}


Side note: The if (block.length < 4) is unnecessary, with the check it cannot be true. (Just calling blockBuilder again without doing anything with its result wouldn't have helped anyway.)

Side note 2: Your randomChar function picks either a letter or a number (digit), giving each a 50/50 chance. That reduces the uniqueness of your strings, by limiting to only 10 choices half the time. You might consider doing what Barmar asked about and just adding the digits to your overall list, which would A) Make the implementation simpler, and B) Spread things more evenly amongst the 36 choices.

For instance:

var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".split("");

function blockBuilder() {
  var block = randomChar() + randomChar() + randomChar() + randomChar();
  return block;
}

function idBuilder() {
  return blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder() + "-" + blockBuilder()
}

function randomChar() {
  return chars[Math.floor(Math.random() * chars.length)];
}

for (var i = 0; i < 100; i++) {
  var v = idBuilder();
  document.write(v + "<br>");
}

Upvotes: 6

Maciej Kwas
Maciej Kwas

Reputation: 6419

At a first glance it seems to me that sometimes you will get only numbers thus javascript engine will convert it somewhere in between into number like 2+1+2+9 => 14 instead of 2129, try something like this in place of randomChar() function and you wouldn't even need to check the length: return Math.floor(Math.random() * 2) == 0 ? randomLetter() : randomNumber().toString();

Upvotes: 1

Related Questions