最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - generate unique ids js - Stack Overflow

programmeradmin2浏览0评论

Running some tests in Jasmine to try to get this code to work, discovered that ids were not unique. Which makes sense since they are generated randomly like so.

var Robot = function(){
    this.name = makeid();
    function makeid()
    {
        var text = "";
        var possible ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for( var i=0; i < 2; i++ ){
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        }
        var possibleNums ="0123456789";
        for( var j=0; j < 3; j++ ){
            text += possibleNums.charAt(Math.floor(Math.random() * possibleNums.length));
        }
        return text;
    }
};

I need it to fulfill this test.

it('there can be lots of robots with different names each', function() {
    var i,
        numRobots = 10000,
        usedNames = {};

    for (i = 0; i < numRobots; i++) {
      var newRobot = new Robot();
      usedNames[newRobot.name] = true;
    }
    expect(Object.keys(usedNames).length).toEqual(numRobots);
  });

I theorized that I might be able to make an array, push each name to it, and then compare for uniqueness. That looks like it might be frustrating. I'm wondering if there's another way, maybe to guarantee uniqueness at generation or some simple comparison tool not involving arrays.

Edit: The date stamp method would be a great way of ensuring unique ids but unfortunately I have to use the id generation method I used to pass another test. Essentially I need the id to be 5 chars with 2 capital letters followed by 3 numbers.

Running some tests in Jasmine to try to get this code to work, discovered that ids were not unique. Which makes sense since they are generated randomly like so.

var Robot = function(){
    this.name = makeid();
    function makeid()
    {
        var text = "";
        var possible ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for( var i=0; i < 2; i++ ){
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        }
        var possibleNums ="0123456789";
        for( var j=0; j < 3; j++ ){
            text += possibleNums.charAt(Math.floor(Math.random() * possibleNums.length));
        }
        return text;
    }
};

I need it to fulfill this test.

it('there can be lots of robots with different names each', function() {
    var i,
        numRobots = 10000,
        usedNames = {};

    for (i = 0; i < numRobots; i++) {
      var newRobot = new Robot();
      usedNames[newRobot.name] = true;
    }
    expect(Object.keys(usedNames).length).toEqual(numRobots);
  });

I theorized that I might be able to make an array, push each name to it, and then compare for uniqueness. That looks like it might be frustrating. I'm wondering if there's another way, maybe to guarantee uniqueness at generation or some simple comparison tool not involving arrays.

Edit: The date stamp method would be a great way of ensuring unique ids but unfortunately I have to use the id generation method I used to pass another test. Essentially I need the id to be 5 chars with 2 capital letters followed by 3 numbers.

Share Improve this question edited May 12, 2016 at 2:06 Zack Lucky asked May 11, 2016 at 22:09 Zack LuckyZack Lucky 6713 gold badges10 silver badges25 bronze badges 3
  • add to the generated code a unique number like [generateId]+"00001" and so on ...[generateId]+"00002" , [generateId]+"00003"... but this is more like a shortcut, a bad one :) – DIEGO CARRASCAL Commented May 11, 2016 at 22:15
  • you can use any GUID library to create a unique name or just use this.name = Robot.totalCount++ – Bryan Chen Commented May 11, 2016 at 22:27
  • Possible duplicate of Create GUID / UUID in JavaScript? – Heretic Monkey Commented May 11, 2016 at 22:38
Add a comment  | 

5 Answers 5

Reset to default 9

Instead of using your custom unique ID generation system, you could use Date.now(), which returns the date and time in milliseconds like this: 1463004819469.

Date.now() changes every millisecond, and is always unqiue. Assuming that you program doesn't have multiple threads, things have to be done in order, so there will be no two IDs the same.

For example:

var Robot = function(){
    this.name = Date.now(); //1463004819469
}

Hope this solves your problem!


Edit: if you call new Robot() twice in a a row, you are likely to get the same IDs. You could use a concatenate Date.now() to a custom unique ID or random number, like one of these:

  • this.name = String(Date.now())+Math.floor(Math.random()*10000);
  • this.name = String(Date.now())+makeid();
  • this.name = String(Date.now())+String(counter); //increment this every time you create a Robot

These are just examples, and you could create any combination you would like.

To be honest, why don't you just use a counter? Like this:

var counter = 0;
var Robot = function(){
    counter++;
    this.name = counter;
}

Unless the IDs exist outside of the program too, so in that case, that wouldn't work.

I know the question was more specific but maybe someone like me is just looking for short way to get ID. I've found a solution from gist.github.com/gordonbrander/2230317 by gordonbrander/ID.js

  var ID = function () {
  // Math.random should be unique because of its seeding algorithm.
  // Convert it to base 36 (numbers + letters), and grab the first 9 characters
  // after the decimal.
  return '_' + Math.random().toString(36).substr(2, 9);
};

Slightly modifying your code you can get guaranteed unique ids but i wouldn't recommend this for a big army of robots like 100000+ since it gets painfully slow.

var Robot = function(){
    this.name = this.makeId();
};

Robot.prototype.makeId = function makeId(){
  var     text = "",
      possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  possibleNums = "0123456789";
  for( var i=0; i < 2; i++ ){
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }

  for( var j=0; j < 3; j++ ){
    text += possibleNums.charAt(Math.floor(Math.random() * 10));
  }
return !~Robot.prototype.ids.indexOf(text) ? (Robot.prototype.ids.push(text),text) : makeId();
};

Robot.prototype.ids = [];

function robotFactory(n){
  a = [];
  for(var i = 0; i < n; i++) a.push(new Robot());
  return a;
}

var myRobotArmy = robotFactory (10000);

Edit @ August 18, 2017

Checking the above code i've thought i could have done much better. Especially at the indexOf part which is a huge bottleneck on performance. Now it runs much faster. Also i could have shaped up the constructor function better by hiding unnecessary data and functionality from the access of instantiated objects by making them private. Another thing is the required naming scheme allows only 676,000 names (26 x 26 x 10 x 10 x 10) so asking for more robots than that will result stack overflow since we will have all possible names yet keep trying to generate a unique one. This of course can be prevented by limiting the army size from the very beginning. But then think about asking for an army of 676,000 robots. The failure rate of the random name generator will increase as the used names stack up in the hash table. As per last name we will have to try may hundreds of thousands random names up until we get the last unique one. In this particular cases you have two solutions;

1) If you want robots in the scale of 1M then make your naming at least in the form of XYZ123 2) If you will use the most of available naming scheme like XY123 and you want 600K robots then assign the names not randomly but in order.

function Robot(){
 this.name = Robot.makeId();
}

Robot.nums   = Array.from({length:10},(_,i) => i);
Robot.chars  = Array.from({length:26},(_,i) => String.fromCharCode(65+i));
Robot.idmap  = {};
Robot.makeId = function(){
                 var text = Array.from({length:2}, _ => Robot.chars[~~(Math.random()*26)]).join("") +
                            Array.from({length:3}, _ => Robot.nums[~~(Math.random()*10)]).join("");
                 return !Robot.idmap[text] ? (Robot.idmap[text] = true,text) : Robot.makeId();
               };

function robotFactory(n){
  a = [];
  for(var i = 0; i < n; i++) a.push(new Robot());
  return a;
}

var myRobotArmy = robotFactory(10);
console.log(myRobotArmy);

If you just want an id that is unique to your own page, you can do that very simply with just a counter:

var unique = (function() {
    var cntr = 0;
    return function(prefix) {
        prefix = prefix || "";
        return prefix + cntr++;
    }
})();

console.log(unique("myid"));   // "myid0"
console.log(unique("myid"));   // "myid1"

Using that in your code:

var unique = (function() {
    var cntr = 0;
    return function(prefix) {
        prefix = prefix || "";
        return prefix + cntr++;
    }
})();

var Robot = function(){
    this.name = unique("robot");
};

A monotonically increasing counter is all you need to make sure you generate unique names within this scope.


If you want to generate strings that are highly likely to be unique among all clients, you can use something like found in these answers:

Unique Random DIV ID

unique random array javascript

Generating random numbers on different input texts and ensuring random numbers shown are unique

If you want a complete guarantee among all pages/users in the world, then you have to either use a central server to coordinate and assign unique values or use some known unique client seed (it is common for GUID generators on a PC to use an ethernet mac address as a seed since those are not repeated for other computers).

This is the function I use in my JS code:

function uniqueid() {
    // always start with a letter (for DOM friendlyness)
    var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
    do {
        // between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
        var ascicode = Math.floor((Math.random() * 42) + 48);
        if (ascicode < 58 || ascicode > 64) {
            // exclude all chars between : (58) and @ (64)
            idstr += String.fromCharCode(ascicode);
        }
    } while (idstr.length < 32);

    return (idstr);
}
发布评论

评论列表(0)

  1. 暂无评论