SOFTELメモ

Softel Inc.

【Javascript】配列の順序のランダム入れ替え

問題

phpだと shuffle($array)で配列の内容をランダムな順序に入れ替えられるじゃないですか。

Javascriptでも配列の要素のランダム入れ替えってできる?

[0,1,2,3,4,5,6,7,8,9] → [4,6,8,0,9,3,7,1,2] のような感じ。

答え

shuffle()関数で配列の要素をシャッフルできるのは、便利機能満載、関数の塊のphpならではの風景。

JavascriptのArrayオブジェクトにshuffleはない。実装方法も考えて自分で作る必要がある。

乱数で重みをつけて並べ替える方法

var x = [0,1,2,3,4,5,6,7,8,9];
//配列xの各要素に乱数で重みをつける
for (var i = 0, l = x.length; i < l; ++i) {
	x[i] = [x[i], Math.random()];
}
//配列xを重みによってソートする
x.sort(function(a, b){return a[1] - b[1];});
//配列xを元の形に戻したいので、重み部分のデータを取り除く
for (var i = 0, l = x.length; i < l; ++i) {
	x[i] = x[i][0];
}
//xの要素はランダムな順序に入れ替えられた
alert(x);

シュワルツ変換というらしい。

Javascript1.6以降で、Array.mapメソッドがあれば1行で書ける。

var x = [0,1,2,3,4,5,6,7,8,9]
x = x.map(function(a){return {weight:Math.random(), value:a}})
        .sort(function(a, b){return a.weight - b.weight})
        .map(function(a){return a.value});
alert(x);
var x = [0,1,2,3,4,5,6,7,8,9]
x = x.map(function(a){return [a, Math.random()]})
            .sort(function(a, b){return a[1] - b[1]})
            .map(function(a){return a[0]});
alert(x);

Arrayのメソッドとして x.shuffle() のような呼び出し方をしたい場合は、以下のようにする。

Array.prototype.shuffle = function() {
    return this.map(function(a){return [a, Math.random()]})
                .sort(function(a, b){return a[1] - b[1]})
                .map(function(a){return a[0]});
}
var x = [0,1,2,3,4,5,6,7,8,9];
alert(x.shuffle());

Fisher-Yatesというアルゴリズムを使った例

Array.prototype.shuffle = function() {
    var i = this.length;
    while(i){
        var j = Math.floor(Math.random()*i);
        var t = this[--i];
        this[i] = this[j];
        this[j] = t;
    }
    return this;
}
var x = [0,1,2,3,4,5,6,7,8,9];
x.shuffle();
alert(x);

ランダム番目を取り出していく方法

Array.prototype.shuffle = function(){
    var l = this.length;
    var a = this.concat();
    var r = [];
    while(l) r.push(a.splice(Math.floor(Math.random() * l--), 1));
    return r;
}
var x = [0,1,2,3,4,5,6,7,8,9];
y = x.shuffle();
alert(y);

関連するメモ

コメント