打字稿随机数生成问题
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;
}
请注意,我将 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
这让我抓狂,因为我不明白为什么这不起作用!
要求很简单:机器人在其名称重置后(通过调用 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;
}
请注意,我将 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