JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで配列をランダムにシャッフルする方法!_.shuffle()とFisher-Yatesアルゴリズムを解説

JavaScriptで配列をシャッフルする基本:_.shuffle()

JavaScriptで配列の要素の順番をランダムに入れ替えたい場合、Underscore.jsLodashといった定番のユーティリティライブラリが提供する_.shuffle()関数を使うのが手軽です。この関数は内部でFisher-Yates(フィッシャー–イェーツ)シャッフルと呼ばれるアルゴリズムを採用しており、すべての並び順が等しい確率で現れる、偏りのないシャッフルを実現できます。

構文

_.shuffle(array);

引数にはシャッフルしたい配列を渡します。戻り値として、要素がランダムに並べ替えられた新しい配列が返されます。同じ入力を渡しても、実行するたびに異なる結果が得られるのが特徴です。

サンプルコード1:文字列の配列をシャッフルする

<html>
<body>
<script type="text/javascript"
    src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/0.10.0/lodash.min.js"></script>
<script>
    document.write(_.shuffle(["raj", "pankaj", "rahim", "rachel", "Balakrishna"]));
</script>
</body>
</html>

出力結果

rahim,Balakrishna,pankaj,raj,rachel

このように、ページを読み込むたびに要素の並び順が変化します。

オブジェクトの配列もシャッフルできる

_.shuffle()は文字列や数値だけでなく、オブジェクトが格納された配列にもそのまま使えます。以下の例では、名前と年齢を持つ人物データの配列をランダムに並べ替えています。

サンプルコード2:オブジェクト配列をシャッフルする

<html>
<body>
<script
    src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/0.10.0/lodash.min.js"></script>
<script>
    var people = [
        {"name": "Ram", "age": 27},
        {"name": "Rahim", "age": 28},
        {"name": "Rakul", "age": 29},
        {"name": "Rohti", "age": 21}
    ];
    document.write(JSON.stringify(_.shuffle(people)));
</script>
</body>
</html>

出力結果

[{"name":"Rahim","age":28},{"name":"Rakul","age":29},{"name":"Ram","age":27},{"name":"Rohti","age":21}]

オブジェクトの中身はそのままに、配列内の順序だけがランダムに入れ替わっていることが分かります。

Fisher-Yatesシャッフルとは?

Fisher-Yatesシャッフルは、あらゆる並び順が数学的に等しい確率で生成されることが保証された、最も信頼性の高いシャッフル手法です。計算量はO(n)と非常に効率的で、要素数の多い大きな配列でも高速に動作します。_.shuffle()は大規模なデータに対してもこのアルゴリズムを利用しているため、パフォーマンス面でも安心して使えます。

ライブラリを使わず自前でシャッフルする方法

外部ライブラリを導入したくない場合は、Fisher-Yatesアルゴリズムを素のJavaScriptで簡単に実装することもできます。

function shuffle(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
}

console.log(shuffle([1, 2, 3, 4, 5])); // 実行例: [3, 1, 5, 2, 4]

この実装では、配列の末尾から先頭に向かって各要素を、それより前の位置(自分自身を含む)にある要素とランダムに入れ替えていくことで、完全なランダム性を実現しています。

まとめ

・手軽にシャッフルしたいならUnderscore.js / Lodashの_.shuffle()が便利
・内部では偏りのないFisher-Yatesシャッフルが採用されている
・文字列・数値・オブジェクトなど、どんな配列でもシャッフル可能
・ライブラリ不要の場合は、Fisher-Yatesを自前実装するのも有効な選択肢

  1. JavaScriptで配列をセット(Set)に変換する方法|new Set()の使い方を解説

    JavaScriptでは、new Set() コンストラクタを使うことで、配列を簡単にセット(Setオブジェクト)へ変換できます。セットは同じ値を自動的に1つだけ保持する性質を持つため、配列から重複した要素を取り除きたい場合にも非常に便利です。 配列をセットに変換するサンプルコード 以下は、ボタンをクリックすると配列がセットに変換されて表示される、完全なHTMLサンプルです。 <!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name=viewport co

  2. JavaScriptでIDごとにオブジェクトの配列をグループ化する方法

    JavaScriptでオブジェクトの配列をidなどの特定のキーごとにグループ化したい場合、reduce()メソッドを使うと簡潔に実装できます。この記事では、どのプロパティにも対応できる汎用的なgroupBy関数を作成し、実際のサンプルコードとともにその仕組みを詳しく解説します。 reduce()によるグループ化の考え方 reduce()は、配列の各要素を順番に処理しながら、1つの累積値(ここではオブジェクト)を組み立てていくメソッドです。各要素からキーの値を取り出し、その値がまだ結果オブジェクトに存在しなければ新しい配列を作成して、そこへ要素を追加していくことでグループ化を実現します。 サ