#はじめに
randomで値を取ってきても、重複して困るってこと結構ありませんか?
#なんのために必要か?
自分はテニスが好きで、スクールに通ったり、地域のテニスイベントに参加したりしている。スクールはさておき、テニスイベントでは最後に参加者をランダムでダブルスの試合をするのだが、参加者が多いと、ダブルスのペアを考えるのが大変😩
そこで、手軽に持ち運びのできるiPhoneでそういったアプリを乱数を使って作れば、かなり需要があるんじゃねと思い作り始めました。
#ぶつかった壁
乱数を取ってペアを作ること自体は簡単でした。
実際、このようなソースでランダムに4人取ることができます。
func makeDouble(Num:Int) {
var intArray: [Int]
intArray = []
var intset: [Int]
intset = []
if Num < 4 {
displayAlert()
}else{
intArray = []
for i in 1...Num{
intArray.append(i)
}
//
for _ in 0..<4{
let j = Int(arc4random_uniform(UInt32(intArray.count)))
intset.append(intArray[j])
}
}
}
これだとどういった問題が出てくるのかと言うと、重複(同じ数が複数回出てきてしまう。)問題が発生するのだ。
実際、このソースで動かしてみると結果は以下のようになる
[4, 10, 9, 1]
[4, 6, 9, 8]
[6, 4, 10, 10]
[8, 9, 4, 10]
[1, 7, 3, 7]
[9, 6, 1, 1]
[9, 5, 8, 5]
[6, 4, 3, 6]
[3, 10, 2, 6]
[1, 10, 8, 1]
10人でシャッフルした場合は重複が少ないように見えるが、これが5人だった場合には
[2, 3, 5, 1]
[2, 4, 4, 3]
[2, 3, 5, 2]
[2, 5, 1, 4]
[5, 2, 5, 1]
[1, 3, 4, 3]
[3, 3, 4, 5]
[5, 2, 3, 5]
[4, 5, 1, 2]
[4, 2, 5, 2]
とかなりの確率で重複した値が出てきてしまう。
#じゃあどうするか?
巷では、重複をチェックするのに2重ループを回して重複の有無をチェックするやり方が
ちらほらと見受けられるが、もっとスマートにやりたい。
と色々試行錯誤してある方法を思いついた。
配列に値を入れてそこからランダムに値を入れて、それを配列から削除すれば、重複なくなるんじゃねと
実際に書いたソースがこちら
func makeDouble(Num:Int) {
var intArray: [Int]
intArray = []
var intset: [Int]
intset = []
if Num < 4 {
displayAlert()
}else{
intArray = []
for i in 1...Num{
intArray.append(i)
}
//
for _ in 0..<4{
let j = Int(arc4random_uniform(UInt32(intArray.count)))
intset.append(intArray[j])
intArray.remove(at: j)
}
}
}
実際に重複した値が出てこないかチェックする。
先ほどと同じく5人、10人でチェックする(試行回数は10回)
[8, 7, 2, 10]
[5, 3, 10, 9]
[10, 4, 5, 1]
[1, 8, 4, 3]
[10, 4, 2, 7]
[6, 8, 2, 3]
[10, 6, 8, 2]
[3, 10, 7, 8]
[1, 9, 3, 7]
[8, 7, 4, 2]
[5, 1, 4, 3]
[2, 1, 3, 4]
[2, 5, 3, 4]
[1, 5, 3, 2]
[1, 2, 5, 3]
[2, 1, 5, 4]
[3, 5, 4, 1]
[1, 4, 3, 2]
[5, 4, 1, 2]
[4, 3, 5, 1]
これで重複は無くなった。(数字に偏りはあるが😅)
今回作ったアプリはこちらで公開してます。
https://github.com/tnatsume/ShuffleDoubles