2017/02/01

【JavaScript】配列のシャッフルする(要素をランダムに並び替える)

重複なく、かつランダムな値がほしいときがある。たとえばトランプのカード(1〜13)をランダムに取得したい場合などだ。
そんなときに使える関数を、lodash、ES2015(ES6)、ES5(レガシーブラウザ対応)でそれぞれ実装してみた。

ちなみに今回シャッフルさせるために使ったアルゴリズムは「Fisher-Yatesのシャッフル」という名前がついているらしい。

lodashをつかった場合


const values = [1,2,3,4,5,6,7,8,9,10];

const shuffledByLodash = _.shuffle(values);
console.log(...shuffledByLodash);

シンプルにワンライナーでかける。
さすがlodash



ES2015(ES6)をつかった場合


const shuffleByES6 = array => {
  // deep copy
  const ary = array.slice();
  for (let i = ary.length - 1; 0 < i; i--) {
    let r = Math.floor(Math.random() * (i + 1));
    // ary[i] <-> ary[r]
    [ary[i], ary[r]] = [ary[r], ary[i]];
  }
  return ary;
}
const shuffledByES6 = shuffleByES6(values);
console.log(...shuffledByES6);

3行目: 配列は参照渡しになっているので、関数内で引数の配列をいじると元の配列valuesまで変わってしまう。
そこでArray.slice()を使うことでディープコピー的なことをしている。Array.concat()を使うことでも同じことが実装できる。

7行目: ES2015から使えるようになった分割代入構文をつかって値の入れ替えを行っている。分割代入構文を使うとテンポラリ変数を用意しなくて済むのでスッキリする。

ただし注意点が。。。
普通にJavaScriptを実装している人には問題ないが、直前のステートメントにセミコロンを付けないと…。



ES5をつかった場合


var shuffleByES5 = function (array) {
  // deep copy
  var ary = array.slice();
  for (var i = ary.length - 1; 0 < i; i--) {
    var r = Math.floor(Math.random() * (i + 1));
    // ary[i] <-> ary[r]
    var temp = ary[i];
    ary[i] = ary[r];
    ary[r] = temp;
  }
  return ary;
};
var shuffledByES5 = shuffleByES5(values);
console.log(shuffledByES5.join(',');

ES2015で分割代入を使っていたところを、定番の値入れ替え処理に変えただけ。


今回紹介したのは配列の中身をシャッフルするだけだったが、重複なくランダムに値が欲しいだけだったらArray.splice(random, 1)みたいにしても実現できる。



参考サイト




以上

written by @bc_rikko

0 件のコメント :

コメントを投稿