Javascript プログラミング

配列をいじらずに、代わりに対応するインデックスをソートする

配列の順番をランダム化、ソート、リセットしたい

クイズ的なアプリを作っているときに、配列に入った問題をランダムに並び替えたり、アルファベット順に並べたり、再び元に戻したりしたいと思いました。

配列のランダム化(シャッフル)

配列のランダム化はググると出てくる有名なアルゴリズム(Fisher–Yates)があるのでそれを使います。

  const array = [1,2,3,4,5];
  for (let i = array.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1)); // 0 から i のランダムなインデックス
    [array[i], array[j]] = [array[j], array[i]]; // 要素を入れ替え
  }
  console.log(array);

ただ、問題の入った配列を直接並べてしまうと元に戻せなくなってしまいます。

DBから再取得して元に戻すとか、配列を複製してランダム化するとかの方法もありますが、私は問題の配列に対応するインデックス用の配列を用意して、そちらを入れ替える方法を使いました。

オリジナルに手を加えないのでインデックス配列に番号を振り直すだけでオリジナルの順序に戻ります。

var array = ["a", "b", "c", "d", "e"];
var index = [0, 1, 2, 3, 4];

// index[]の順番をランダム化
for (let i = array.length - 1; i > 0; i--) {
  let j = Math.floor(Math.random() * (i + 1)); // 0 から i のランダムなインデックス
  [index[i], index[j]] = [index[j], index[i]]; // 要素を入れ替え
}

// ランダム化したindexを引数にしてarrayを呼び出す
for (let i = 0; i < index.length; i++){
      console.log(array[index[i]]);
}

//result
b
d
e
a
c

配列をソートしたいが、並び替えのキーとなる配列と並び替える配列が別

ランダム化はこれで良かったのですが、困ったのは問題をアルファベット順や50音順に並べ替えるときです。

ソート時に大小(前後)の比較をする配列はarray[]ですが、実際にソートする配列はindex[]です。

そんなことできるのかなと思って、調べたらsortメソッドに渡す比較関数を工夫するとできることが分かりました。

var array = [5, 2, 1, 4, 3];
var index = [0, 1, 2, 3, 4];

function compare(idx1, idx2) {
  return array[idx1] - array[idx2];
}
index.sort(compare);

for (let i = 0; i < index.length; i++){
      console.log(array[index[i]]);
}

1
2
3
4
5

index.sortに渡す比較関数の中でarray[]を比較します。

ただ、この比較関数は単純な引き算なので数値データ専用です。

array[]の中身が文字列だとちゃんとソートできません。

調べてみると、文字列の場合は.localCompare()というメソッドを使うといいことが分かりました。

第2引数には言語コードを指定します。とりあえず私が使うのは、日本語=ja、英語=en、中国語=zhといった感じ。

var array = ["e", "a", "c", "d", "b"];
var index = [0, 1, 2, 3, 4];

function compare(idx1, idx2) {
   return array[idx1].localeCompare(array[idx2], 'en');
}
index.sort(compare);

for (let i = 0; i < index.length; i++){
      console.log(array[index[i]]);
}

a
b
c
d
e

言語コードのリストがないかなと思って探してみたらありました。

ISO Language Code Table

-Javascript, プログラミング