2018-12-12

JavaScriptでシャッフル&ソート

JavaScript
新人向けTIPS

JavaScript でシャッフルしたい!

ビンゴボール、トランプカードなどのシャッフル。
JavaScript で配列をシャッフルする方法です。
順を追って解説しているので、実装方法だけを知りたい人はシャッフルしてみるまでジャンプしてください。

シャッフルの前に知っておくこと、それは sort

シャッフル実装の前にソートを勉強しましょう。
並びをランダムにしたいシャッフルとは真逆の機能ですが、配列のソート機能を使ってシャッフルを実現します。

Array.prototype.sort

Arrayのプロトタイプにある、sortメソッド。
これは配列内部を直接並び替えます。
コピーを作成するわけではないことに注意してください。

// 配列にソートされていない数字を用意  
const array = [3, 9, 1, 2, 4, 5, 6, 7, 8, 10];  

// sortメソッドを実行すると、配列の中身を直接操作します  
array.sort();  

// 結果: [ 1, 10, 2, 3, 4, 5, 6, 7, 8, 9 ]  
console.log(array);  

さて、上記の結果を見てみると、1の次は10になっていますね。
これはsortメソッドでは文字列としてソートされるためです。
Number で入れているのに。。。

sort には関数を渡せる

数字として比較し、1の次は2になってほしいですね。
sortメソッドには関数を渡せるので、これで結果を変えることができます。

// 配列にソートされていない数字を用意  
const array = [3, 9, 1, 2, 4, 5, 6, 7, 8, 10];  

// 並び替えルールを関数で提供  
array.sort((a, b) => a - b);  

// 結果: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]  
console.log(array);  

sortメソッドに渡す関数は、比較した結果の大小を数字で表現して返す必要があります。
abの2つを比較したとき、aが大きければ0より大きい数字を、bが大きければ0未満の数字、等しければ0を返すようにします。
このサンプルではaからbを引き算した結果を返しています。

これで数字順にソートされた結果を得ることができました。

シャッフルしてみる

上の例から、シャッフルするにはランダムに正の値と負の値を返せばシャッフルできそうです。
JavaScript にはMathオブジェクトにrandom関数があり、0〜1 未満の数をランダムに返してくれます。
そのまま使うと 0 未満の数字は出せないので、-0.5して負の数も返すようにします。
数字の比較はしないので、関数の引数abはなくても大丈夫です。

// 配列にソートされている数字を用意  
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];  

// ランダムに-0.5〜0.5の数字を返す  
array.sort(() => Math.random() - 0.5);  

console.log(array);  
// 結果: [ 7, 3, 8, 2, 4, 6, 5, 1, 9, 10 ]  

これで配列をシャッフルすることができました!

おまけ: 配列に shuffle メソッドを追加実装したい

シャッフルしたいのにsortで呼び出すなんて、ちょっとややこしいですね。
配列のprototypeshuffleメソッドを実装してみましょう。これにより配列インスタンスからshuffleメソッドを使用できるようになります。

// 配列にshuffleメソッドを追加  
Array.prototype.shuffle = function () {  
  this.sort(() => Math.random() - 0.5);  
}  

// 配列にソートされている数字を用意  
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];  

// shuffleメソッドをコール  
array.shuffle();  

console.log(array);  
// 結果: [ 5, 2, 1, 7, 9, 3, 6, 8, 10, 4 ]  

ちゃんとshuffleメソッドが追加されてシャッフルできましたね!


猫派 / 基本インドア / ガジェット大好き / RDP推進派
コロナ禍の趣味はPC+VRでゲーム。
最近のゲーム:Factorio / BeatSaber / にゃんこ大戦争

→ Policy