打字稿随机数生成问题

Typescript random number generation problem

这让我抓狂,因为我不明白为什么这不起作用! 要求很简单:机器人在其名称重置后(通过调用 resetName())应该有一个新的唯一名称。我的逻辑是不断生成一个新名称,并且唯一性由 Set 强制执行。但它不起作用,也就是说,如果我创建一个 Robot 实例,在调用 resetName 10000 次之后,那么应该有 10001 个唯一名称。但事实并非如此; _counter 变量指示仅生成了大约 9920 个随机命名的名称。想不通为什么。

export class Robot {
  private capitals = [...Array(26).keys()].map(i => String.fromCharCode(i + 65)); // generate 26 capital letters.
  private _name = '';
  private static _seen = new Set<string>();
  private _counter: number = 0;
  constructor() {}

    // name is in the format of XXYYY where X is a captial letter and Y is a digit.
  public get name(): string {
    if (!this._name) {
      // continuously generate a new unique name.
      while (!Robot._seen.has(this._name)) {
        this._name = this.capitals[this.randomNumber(25)] + this.capitals[this.randomNumber(25)] + this.randomNumber(9) + this.randomNumber(9) + this.randomNumber(9);
        if (!Robot._seen.has(this._name)) {
          this._counter += 1;
          Robot._seen.add(this._name);
          break;
        } 
      }
    }
    
    return this._name;
  }

  public resetName(): void {
    this._name = '';
  }

  public static releaseNames(): void {
    //Robot._seen.clear();
  }
  
  // generate a random number between min and max inclusively.
  private randomNumber = (max: number, min: number = 0): number => Math.floor(Math.random()*(max - min + 1) + min);
}

这是失败的单元测试:

it('should set a unique name after reset', () => {
    const NUMBER_OF_ROBOTS = 10000
    const usedNames = new Set()

    usedNames.add(robot.name)
    for (let i = 0; i < NUMBER_OF_ROBOTS; i++) {
      robot.resetName()
      usedNames.add(robot.name)
    }

    expect(usedNames.size).toEqual(NUMBER_OF_ROBOTS + 1)
  })

问题是您的 while 初始条件不正确。如果您要使用 while 循环执行此操作,则条件应为:

while (!this._name || Robot._seen.has(this._name)) {

没有

while (!Robot._seen.has(this._name)) {

您需要在 previously-seen 集合 有新名称时继续循环,而不是 没有 .

但是这个逻辑可以大大简化:

public get name(): string {
    if (!this._name) {
        // continuously generate a new unique name.
        let name;
        do {
            name = this.capitals[this.randomNumber(25)] + this.capitals[this.randomNumber(25)] + this.randomNumber(9) + this.randomNumber(9) + this.randomNumber(9);
        } while (Robot._seen.has(name));
        Robot._seen.add(name);
        ++this._counter;
        this._name = name;
    }
    
    return this._name;
}

Playground link

请注意,我将 name 保留在本地,直到我们知道它是独一无二的。如果需要,您可以写信给this._name

public get name(): string {
    if (!this._name) {
        // continuously generate a new unique name.
        do {
            this._name = this.capitals[this.randomNumber(25)] + this.capitals[this.randomNumber(25)] + this.randomNumber(9) + this.randomNumber(9) + this.randomNumber(9);
        } while (Robot._seen.has(this._name));
        Robot._seen.add(this._name);
        ++this._counter;
    }
    
    return this._name;
}

...但是在我确定它们是正确的之前,我不希望将这样的更改提交给对象。 Playground link