Javascript:从数组中随机配对而不重复

时间:2014-01-22 22:14:59

标签: javascript

我正在尝试将一个非常基本的“秘密圣诞老人”生成器作为我的第一个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);

提前感谢您的帮助。

5 个答案:

答案 0 :(得分:1)

使用名称创建两个数组,将它们随机播放,并确保不从两个数组中选择相同的名称:

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);
    }
}

FIDDLE

答案 1 :(得分:1)

我建议采用不同的方法。随机,分裂和拉链,没有突变:

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' ]
// ]

答案 2 :(得分:1)

有很多方法可以实现这一目标。

最快的代码,但不一定是randomest:

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-> D-> E-> D.

如果您希望它具有随机数量的可变长度循环,您可以将names数组拆分为多个数组,并为每个数组执行上述操作,然后连接结果(请参阅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];
}

答案 3 :(得分:0)

如果您不需要保留原始数组,则可以在选择名称时删除这些名称,每次选择名称时,请在将其推送到下一个数组之前检查它是否为空字符串。

答案 4 :(得分: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/