ランダムに部分的に配列を取ってくる
配列から無作為に要素を取ってくる_$O(n^2)$
// fullArrから無作為に重複しないnum個選択したサブセットを返す。
// numをfullArr.lengthにすれば順番をランダムにすることもできる。
// [a,b,c,d] => [c,b]や[d,a]など (num=2のとき)
function randomArray(fullArr, num){
const seq = [...Array(fullArr.length).keys()] // 0からn-1の連番
const arr = []
for(let i=0; i < num; i++){
const iSeq = Math.floor(Math.random() * seq.length)
arr.push(fullArr[seq[iSeq]])
seq.splice(iSeq, 1) // sequenseからは削除
}
return arr
}
↓追記。@nagtkk様よりご指摘いただいた方法。上記は単純実装であり、改良すると計算量が減るとのこと。
配列から無作為に要素を取ってくる_$O(n)$
function randomArray(fullArr, num) {
const arr = fullArr.slice();
for (let i = 0; i < num; i++) {
// i から 最後までの間から 1 つ選び j とする
const j = i + Math.floor(Math.random() * (arr.length - i));
const tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
arr.length = num; // 切り詰める
return arr;
};
文字列をユニークな配列に
文字列.match(/./g)
は文字列を1文字ずつの配列にする。各一文字にマッチするので。
また、Setは(各要素が各々1つの値を持つ?)集合なので重複は削除される。
文字の種類が多い、日本語などで使えそうな関数。
文字列を重複のない1文字ずつの配列にする
// "the str" => [t,h,e, ,s,r]
function uniqueChars(str){
return [...new Set(str.match(/./g))]
}
この関数についても@nagtkk様にご指摘いただき、
Set は、配列でなくとも Iterable (イテレータが取得可能)なら受け取ることができ、文字列はIterable なのでそのまま突っ込めます。
文字列にインデックスアクセスした場合と異なり、サロゲートペア等考えなくてよいです。文字列からイテレータを取得した場合は、Unicode コードポイント単位で分かれてくれます。
とのこと。つまり[...new Set(str)]
で済んでしまうので、関数化しないという選択肢もある。