簡體   English   中英

Javascript:隨機配對數組中的項目而不重復

[英]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]);
}

http://jsfiddle.net/SNJpC/

如果您不需要保留原始數組,您可以在選擇名稱時刪除它們,並且每次選擇名稱時檢查它是否不是空字符串,然后再將其推送到下一個數組。

另一個考慮...

如果您正在嘗試制作“秘密聖誕老人”生成器,通過使用隨機方法,您可以在明年獲得相同的一對,然后……

這是另一種解決方案,您可以在其中獲得所有可能的配對(不重復名稱本身或配對)多年。

 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM