やりたいこと
例えば以下のような配列があったとする。
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
を使用しているため、インデックスの管理が効率的。
- 配列の長さが少ない場合、要求する要素数を注意深く設定する必要がある(特に小さな配列の場合)。
- 整数の除外やオフセットの設定はしていないため、配列の先頭から詳細な参照が必要な場合は注意が必要。