PHPには配列の要素をシャッフルする「shuffle」という関数がありますが、JavaScriptにはないので、メソッドを自作して使っています。
シャッフルというのは要素をランダムにするのではなく、要素の組合せは変えずに順番をランダムにすることです。
[0, 1, 2, 3, 4] を [3, 1, 2, 0, 4]にするような処理です。
ソートを使う方法
私が考えたのは次のような方法です。
配列の要素毎に値をランダムに与えます。
この値でソートすると元の配列がシャッフルされます。
Array.prototype.shuffle = function() {
var array_length, keys, new_array, i;
array_length = this.length;
keys = [];
new_array = [];
for(i = 0; i < array_length; i++) {
keys[i] = [this[i], Math.random()];
}
keys.sort(function(a, b) {
return a[1] - b[1];
});
for(i = 0; i < array_length; i++) {
new_array[i] = keys[i][0];
}
return new_array;
}
var array_length, keys, new_array, i;
array_length = this.length;
keys = [];
new_array = [];
for(i = 0; i < array_length; i++) {
keys[i] = [this[i], Math.random()];
}
keys.sort(function(a, b) {
return a[1] - b[1];
});
for(i = 0; i < array_length; i++) {
new_array[i] = keys[i][0];
}
return new_array;
}
Fisher–Yatesの方法
上の方法でもできますが、どうにも回りくどくスマートではないので、調べてみると「Fisher–Yates shuffle」というアルゴリズムがあるそうです。
要素が5個の場合、5番目の要素とランダムに選んだ要素を交換します。これで5番目の要素は確定。
次に、要素を一つ減らして、4番目の要素と1番目から4番目まででランダムに選んだ要素を交換します。これで4番目の要素は確定。
これを繰り返します。
Array.prototype.shuffle = function() {
//配列内の要素をランダムに並べ替える。
//元の配列に影響する。
//Fisher–Yates shuffle
var i, j, temp;
i = this.length;
while(i) {
j = Math.floor(Math.random() * i);
i--;
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
return this;
}
//配列内の要素をランダムに並べ替える。
//元の配列に影響する。
//Fisher–Yates shuffle
var i, j, temp;
i = this.length;
while(i) {
j = Math.floor(Math.random() * i);
i--;
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
return this;
}
この関数は使う箇所よりも前に書きます。また次のように使います。
arr.shuffle();
省略して書く方法
mapを使うとコードが短くなります。ソートを使う方法を省略して書いてみます。
words = ["ワシントン", "アダムズ", "ジェファーソン", "マディソン", "モンロー"];
new_words = words.map((x) => [x, Math.random()]).sort((a, b) => a[1] - b[1]).map((x) => x[0]);
new_words = words.map((x) => [x, Math.random()]).sort((a, b) => a[1] - b[1]).map((x) => x[0]);
コメント