[英]Javascript: randomly pair items from array without repeats
我正在嘗試制作一個非常基本的“秘密聖誕老人”生成器作為我的第一個 Javascript 項目之一。 我已經搜索了幾個小時來解決這個問題,但到目前為止我沒有找到任何工作。
我有一組需要相互配對的名稱。 我成功地讓他們配對,但現在有人可以被抽兩次。 我將隨機選擇的名稱推送到另一個數組,但我找不到一種方法來檢查隨機選擇的名稱與已經選擇的名稱。
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*names.length)
if(names[random] == names[i]) {
names[random] = names[random++];
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
} else {
picks.push(names[i] + " gets " + names[random]);
used.push(names[random]);
}
}
console.log("picked array: ")
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
console.log("used array: " + used);
預先感謝您的任何幫助。
使用名稱創建兩個數組,將它們打亂,並確保不要從兩個數組中選擇相同的名稱:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
} else {
var arr1 = names.slice(), // copy array
arr2 = names.slice(); // copy array again
arr1.sort(function() { return 0.5 - Math.random();}); // shuffle arrays
arr2.sort(function() { return 0.5 - Math.random();});
while (arr1.length) {
var name1 = arr1.pop(), // get the last value of arr1
name2 = arr2[0] == name1 ? arr2.pop() : arr2.shift();
// ^^ if the first value is the same as name1,
// get the last value, otherwise get the first
console.log(name1 + ' gets ' + name2);
}
}
我會建議一種不同的方法。 隨機播放、拆分和壓縮,沒有突變:
var splitAt = function(i, xs) {
var a = xs.slice(0, i);
var b = xs.slice(i, xs.length);
return [a, b];
};
var shuffle = function(xs) {
return xs.slice(0).sort(function() {
return .5 - Math.random();
});
};
var zip = function(xs) {
return xs[0].map(function(_,i) {
return xs.map(function(x) {
return x[i];
});
});
}
// Obviously assumes even array
var result = zip(splitAt(names.length/2, shuffle(names)));
//^
// [
// [ 'Nick', 'Kimmy' ],
// [ 'Sean', 'Johnny' ],
// [ 'Kyle', 'Brian' ],
// [ 'Cotter', 'Pat' ],
// [ 'Emily', 'Jeremy' ]
// ]
有多種方法可以實現這一目標。
最快的編碼,但不一定是最隨機的:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
function getPicks(names) {
return names.slice(0).sort(function(){ return Math.random()-0.5 }).map(function(name, index, arr){
return name + " gets " + arr[(index+1)%arr.length];
});
}
getPicks(names);
這不是很隨機,因為洗牌不是很好,也因為你每次都得到一個循環。 不可能有兩個循環 A->B->C->A D->E->D。
如果您希望它具有隨機數量的可變長度循環,您可以將名稱數組拆分為幾個數組並為每個數組執行上述操作,然后連接結果(參見 elclanrs)。
最后,最后一個解決方案是每個人隨機選擇一個人,如果是同一個人,只需再次選擇。 如果兩個數組中剩余的姓氏相同,只需將其與另一對交換即可。
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
var a = names.slice(0);
var b = names.slice(0);
var result = [];
while (a.length > 1) {
var i = extractRandomElement(a);
var j = extractRandomElement(b);
while (i===j) {
b.push(j);
j = extractRandomElement(b);
}
result.push({ a:i, b:j });
}
if (a[0] === b[0]) {
result.push({ a:a[0], b:result[0].b });
result[0].b = a[0];
} else {
result.push({ a:a[0], b:b[0] });
}
var pairs = result.map(function(item){ return item.a + ' gets ' + item.b});
function extractRandomElement(array) {
return array.splice(Math.floor(Math.random()*array.length),1)[0];
}
我有點晚了,但我想我會把我的答案放在這里。 它本質上與@adeneo 做的事情相同,但它使用與 OP 相同的基本代碼:
var names = ["Sean","Kyle","Emily","Nick","Cotter","Brian","Jeremy","Kimmy","Pat","Johnny"];
pickpool = names.slice(0); // Slice the array at the first element to copy it by value
var used = [];
var picks = [];
if (names.length % 2 != 0) {
alert("You must have an even number of names. You currently have " + names.length + " names.");
}
for( var i = 0; i < names.length; i++){
var random = Math.floor(Math.random()*pickpool.length)
if(names[random] == names[i]) {
// names[random] = names[random++];
picks.push(names[i] + " gets " + pickpool[random++]);
pickpool.splice(random++,1);
} else {
picks.push(names[i] + " gets " + pickpool[random]);
pickpool.splice(random,1);
}
}
console.log("picked array: ");
for(var k=0; k<picks.length; k++) {
console.log(picks[k]);
}
如果您不需要保留原始數組,您可以在選擇名稱時刪除它們,並且每次選擇名稱時檢查它是否不是空字符串,然后再將其推送到下一個數組。
另一個考慮...
如果您正在嘗試制作“秘密聖誕老人”生成器,通過使用隨機方法,您可以在明年獲得相同的一對,然后……
這是另一種解決方案,您可以在其中獲得所有可能的配對(不重復名稱本身或配對)多年。
var names = ["Sean", "Kyle", "Emily", "Nick", "Cotter", "Brian", "Jeremy", "Kimmy", "Pat", "Johnny"]; if (names.length % 2 != 0) { alert("You must have an even number of names. You currently have " + names.length + " names."); } else { const arr1 = names.slice() let arr2 = names.slice(); let countDown = number => { if (number === 1) { return; } const last = arr2.pop([number - 1]); arr2.unshift(last); let pairs = []; arr1.map(item => { const index = arr1.indexOf(item); pairs.push(`${arr1[index]} gets ${arr2[index]}`) }) console.log(pairs) return countDown(number - 1); } countDown(names.length) }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.