LoginSignup
1
1

More than 3 years have passed since last update.

js ランダム部分配列 / 文字列を文字単位でユニーク

Last updated at Posted at 2021-02-04

ランダムに部分的に配列を取ってくる

フィッシャー–イェーツのシャッフル

配列から無作為に要素を取ってくる_$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)]で済んでしまうので、関数化しないという選択肢もある。

1
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1