2014-01-22 89 views
4

我正在嘗試將一個非常基本的「祕密聖誕老人」生成器作爲我的第一個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); 

非常感謝您的幫助。

+4

簡單的解決方案:只要洗牌整個陣列(這絕對避免重複),然後配對起來。 – Bergi

+0

什麼可能更容易是隨機化你的名字數組,然後循環,並以這種方式配對。 – brouxhaha

+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

+0

真棒 - 作品像魅力。謝謝! –

+1

你不需要偶數個名字。你至少需要2個。 – Tibos

+0

你可以在一個非常邊緣的情況下得到相同的名字:'arr1:[a,b,c] arr2:[b,a,c]'(排序後)。查看我的答案,找到適用於此的解決方案。 – Tibos

0

如果您不需要保留原有的陣列可以去掉名字,因爲他們得到選擇,你選擇一個名稱檢查每一次,這不是它推到下一個陣列之前,一個空字符串。

+0

如果刪除名稱,則不會有任何空字符串。 – brouxhaha

+0

我最初以爲從數組中刪除名稱,如果它是隨機選擇的,但也會從該圖中消除該人。每個人都需要繪製一個人並繪製。刪除它們可以消除第一部分的問題。 –

+0

@brouxhaha - 很對,數組會變短。 –

1

我會建議不同的方法。隨機,分割和zip,無突變:

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

+0

也很有用 - 它實際上非常有幫助,因爲我剛剛花了幾分鐘的時間試圖破譯@ adeneo的解決方案。 –

相關問題