やりたいこと
例えば以下のような配列があったとする。
const fruits = [ "りんご", "バナナ", "オレンジ", "いちご", "ぶどう", "メロン", "パイナップル", "マンゴー", "スイカ", "さくらんぼ" ];
この中から重複せずにランダムに3つ取得したい。
コード
function getRandomElements<T>(arr: T[], count: number): T[] { if (count > arr.length) { throw new Error('Count is greater than the array length'); } const result: T[] = []; const usedIndices: Set<number> = new Set(); while (result.length < count) { const randomIndex = Math.floor(Math.random() * arr.length); if (!usedIndices.has(randomIndex)) { usedIndices.add(randomIndex); result.push(arr[randomIndex]); } } return result; }
実行すると
getRandomElements(fruits, 3) > ['さくらんぼ', 'ぶどう', 'マンゴー'] getRandomElements(fruits, 2) > ['りんご', 'パイナップル']
のようにできる。
コードの解説
getRandomElements<T>(arr: T[], count: number): T[]関数の定義:- ジェネリック型
<T>を使って、任意の型の配列を受け取れるようにする。
- ジェネリック型
- 引数のチェック:
if (count > arr.length)で、要求した要素数が配列の長さを超えないことを確認。超えた場合はエラーをスロー。
- 結果を格納するための配列
resultと、使用したインデックスを管理するためのSet型のusedIndicesを定義。 - ランダムな要素を取得するループ:
while (result.length < count)で、必要な数のランダムな要素が取得できるまでループ。- 各ループ内で、
Math.random()を使ってランダムなインデックスを生成。 - そのインデックスが
usedIndicesに存在しない場合のみ、結果に追加する。
- 最終的に、重複のないランダム要素が含まれた配列を返す。
注意点
- 重複を避けるために、配列の長さより多くの要素を要求しないこと。
Setを使用しているため、インデックスの管理が効率的。- 配列の長さが少ない場合、要求する要素数を注意深く設定する必要がある(特に小さな配列の場合)。
- 整数の除外やオフセットの設定はしていないため、配列の先頭から詳細な参照が必要な場合は注意が必要。