使用函数发生器和Set的组合。
工作示例:
function randomNumber(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function* uniquePair(max) {
const pairs = new Set();
const maxPairs = max * max;
while (true) {
const res = [randomNumber(max), randomNumber(max)];
const resStr = res.join(",");
switch (true) {
case !pairs.has(resStr):
pairs.add(resStr);
yield res;
break;
case pairs.size === maxPairs:
//done
return;
default:
console.log(resStr + " Exists...");
}
}
}
const gen10 = uniquePair(10);
const si = setInterval(function() {
const next = gen10.next();
if (next.done === true) {
clearInterval(si);
console.log("Done");
} else {
console.log(next.value);
}
}, 500);
.as-console-wrapper { max-height: 100% !important; top: 0; }
这是如何运作的?
const gen = uniquePair(10);
这将为给定的最大范围创建一个新的生成器。
function* uniquePair(max) {
const pairs = new Set();
const maxPairs = max * max;
/** more code **/
}
前两行只创建一次。记住已经创建的pairs唯一组合(开始时为空)并maxPairs了解最大可能的唯一组合。
function* uniquePair(max) {
/** more code **/
while (true) {
const res = [randomNumber(max), randomNumber(max)];
const resStr = res.join(",");
/** more code **/
}
}
在这里,我们创建了一个无限循环。每个循环我们创建两个值的随机组合。我们还创建了这两个值的字符串表示形式(例如:[1,0] -> "1,0")。
function* uniquePair(max) {
/** more code **/
while (true) {
/** more code **/
switch (true) {
case !pairs.has(resStr):
pairs.add(resStr);
yield res;
break;
/** more code **/
}
}
}
对于 while 循环的每次迭代,我们检查两个值的字符串表示是否存在于我们的集合中。如果没有,我们将该字符串表示添加到集合和yield数组中。
yield 是我们暂时“离开”我们的生成器并发回结果的地方,然后可以通过以下方式访问:
const next = gen.next();
//next.value -> [1,0] , next.done -> false
function* uniquePair(max) {
/** more code **/
while (true) {
/** more code **/
switch (true) {
/** more code **/
case pairs.size === maxPairs:
//done
return;
/** more code **/
}
}
}
如果值的字符串表示形式已经存在于我们的集合中,我们检查该集合的大小是否等于最大对数。如果是,我们可以假设没有更多的结果,我们只需return
此时生成器已完成,将不再返回任何值:
const next = gen.next();
//next.value -> undefined , next.done -> true
function* uniquePair(max) {
/** more code **/
while (true) {
/** more code **/
switch (true) {
/** more code **/
default:
console.log(resStr + " Exists...");
}
}
}
如果前面的情况都不匹配,那么我们可以假设 1. 当前组合已经存在,并且 2. 仍然存在组合。然后我们进行下一次循环迭代并提出一个新的组合并重新开始,直到找到一个新的唯一组合。
可运行多个实例:
此代码还允许运行生成器的多个实例,每个实例具有不同的最大数量。
const gen2 = uniquePair(2);
const gen4 = uniquePair(4);
const gen6 = uniquePair(6);
let cycle = 1;
const si = setInterval(function(){
console.log(`Cycle: ${cycle}`);
const next2 = gen2.next();
const next4 = gen4.next();
const next6 = gen6.next();
if(next2.done === false){
console.log(`2: [${next2.value.join(",")}]`);
} else {
console.log("2: DONE");
}
if(next4.done === false){
console.log(`4: [${next4.value.join(",")}]`);
} else {
console.log("4: DONE");
}
if(next6.done === false){
console.log(`6: [${next6.value.join(",")}]`);
} else {
console.log("6: DONE");
}
console.log("-------");
cycle++;
if(cycle === 40) clearInterval(si);
}, 1000);
function randomNumber(max){return Math.floor(Math.random()*Math.floor(max))}
function*uniquePair(max){const pairs=new Set();const maxPairs=max*max;while(!0){const res=[randomNumber(max),randomNumber(max)];const resStr=res.join(",");switch(!0){case!pairs.has(resStr):pairs.add(resStr);yield res;break;case pairs.size===maxPairs:return;}}}
.as-console-wrapper { max-height: 100% !important; top: 0; }
最小最大解决方案:
function randomNumber(max,min) {
return Math.floor(Math.random() * (max - min) + min);
}
function* uniquePair(max, min = 0) {
const pairs = new Set();
const maxPairs = Math.pow(max-min, 2);
console.log(maxPairs);
while (true) {
const res = [randomNumber(max, min), randomNumber(max, min)];
const resStr = res.join(",");
switch (true) {
case !pairs.has(resStr):
pairs.add(resStr);
yield res;
break;
case pairs.size === maxPairs:
//done
return;
default:
console.log(resStr + " Exists...");
}
}
}
const gen10 = uniquePair(10,5);
const si = setInterval(function() {
const next = gen10.next();
if (next.done === true) {
clearInterval(si);
console.log("Done");
} else {
console.log(next.value);
}
}, 500);
预先计算所有可能性的解决方案:
我所拥有的主要示例的主要问题是,请求的组合越多,算法就越难找到一个独特的组合。这当然可以忽略不计,如果:
- 不到100对
- 仅请求了 60-70% 的可能匹配项
如果上述两点都是错误的,那么这个解决方案将是最佳的:
function randomNumber(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function generateAllPossibilities(max){
const res = [];
for(let i = 0; i < max; i++){
for(let j = 0; j < max; j++){
res.push([i,j]);
}
}
return res;
}
function* uniquePair(max) {
const pairs = generateAllPossibilities(max);
while (true) {
const len = pairs.length;
if(len === 0) return;
yield pairs.splice(randomNumber(len), 1).shift();
}
}
const gen10 = uniquePair(10);
const si = setInterval(function() {
const next = gen10.next();
if (next.done === true) {
clearInterval(si);
console.log("Done");
} else {
console.log(next.value);
}
}, 200);
.as-console-wrapper { max-height: 100% !important; top: 0; }