生成唯一的id js

新手上路,请多包涵

在 Jasmine 中运行一些测试试图让这段代码工作,发现 ids 不是唯一的。这是有道理的,因为它们是像这样随机生成的。

 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;
    }
};

我需要它来完成这个测试。

 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);
  });

我推测我可以制作一个数组,将每个名称推送到它,然后比较唯一性。这看起来可能令人沮丧。我想知道是否有另一种方法,也许是为了保证生成时的唯一性或一些不涉及数组的简单比较工具。

编辑:日期戳方法将是确保唯一 ID 的好方法,但不幸的是,我必须使用我用来通过另一项测试的 ID 生成方法。本质上,我需要 id 为 5 个字符,后跟 2 个大写字母和 3 个数字。

原文由 Zack Lucky 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 573
2 个回答

稍微修改你的代码,你可以获得有保证的唯一 ID,但我不建议像 100000+ 这样的机器人大军这样做,因为它变得非常慢。

 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);

编辑@2017 年 8 月 18 日

检查上面的代码我认为我可以做得更好。特别是在 indexOf 部分,这是一个巨大的性能瓶颈。现在它运行得更快了。此外,我可以通过将不必要的数据和功能从实例化对象的访问中隐藏起来,从而更好地塑造构造函数,方法是将它们设为私有。另一件事是所需的命名方案只允许 676,000 个名称(26 x 26 x 10 x 10 x 10),因此要求更多的机器人将导致堆栈溢出,因为我们将拥有所有可能的名称,但仍在尝试生成一个唯一的名称。这当然可以通过从一开始就限制军队规模来避免。但是再想一想,要一支由 676,000 名机器人组成的军队。随机名称生成器的失败率将随着使用过的名称在哈希表中的堆积而增加。根据姓氏,我们将不得不尝试数十万个随机名字,直到我们得到最后一个唯一的名字。在这种特殊情况下,您有两种解决方案;

  1. 如果你想要 1M 规模的机器人,那么至少以 XYZ123 的形式命名 2) 如果你将使用大多数可用的命名方案,如 XY123,并且你想要 600K 机器人,那么分配名称不是随机的,而是按顺序.
 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);

原文由 Redu 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用 Date.now() 而不是使用自定义唯一 ID 生成系统,它以毫秒为单位返回日期和时间,如下所示: 1463004819469

Date.now() 每毫秒变化一次,永远不变。假设你的程序没有多线程,事情必须按顺序完成,所以不会有两个 ID 相同。

例如:

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

希望这能解决您的问题!


编辑: 如果您连续两次调用 new Robot() ,您很可能会获得相同的 ID。您可以将 Date.now() 连接到自定义唯一 ID 或随机数,例如以下之一:

  • 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

这些只是示例,您可以创建任何您想要的组合。

老实说,你为什么不直接使用计数器呢?像这样:

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

除非 ID 也存在于程序之外,否则在那种情况下,这是行不通的。

原文由 Luke 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题