2つの配列が同じがどうか判別してみよう

javascript

ちょっとクイズをJavascriptで作っていた時に、2つの配列を一致してるかどうか判別する必要がありました。クイズの正解と解答を配列で管理することにしました。

どういった配列になるのか

実際の処理はもともと質問の正解を配列として用意しておき、クリックした要素のテキストを配列として保存するのだが、1つしか解答できない場合でも複数の解答になる場合でもすべて配列で処理することにしました。 

以下のようなプログラムの内容で、例えば何かの質問に対して都道府県を解答するクイズだったとする。

/*  正解の配列 */
let arrA=["沖縄"];  //解答が1つだけの場合
let arrB=["東京","大阪"];  //解答が複数の場合

/*  チェックした内容を配列として保存 */
let selectA=["東京"]  /* 1つしかチェックできない場合の解答 */
let selectB=["東京","大阪"] /* 複数の解答 */

上記のように正解の配列と実際にクイズの質問に解答した項目を配列として扱い、2つの配列が長さも内容もまったく同じだった場合は正解というロジックを処理することにした。 例えば上記の例の場合、「沖縄」が正解という質問に対して「東京」という1つの解答の配列は一致しないので不正解とし、2つ目の配列は「東京」「大阪」という配列の長さも内容も一致してるので正解となる。

ただし複数選択可能な場合は「東京」「大阪」「名古屋」「北海道」と選択してしまった場合「東京」「大阪」の正解が2つ含まれていても配列の長さが一致しないので不正解とする。

2つの配列を同じと判別する為のロジックとは?

では実際にどう2つの配列が同じがどうかを処理したらいいのかを説明していきます。

every() メソッドとincludes() メソッドを利用して配列を比べる

まずはevery() includes() メソッドについて説明します。

every() メソッドについて

every() は 配列の要素がすべてが、指定した条件を満たしているか否かを確認するメソッドで、すべてを満たしていればtrue、1つでも条件を満たしていない要素があれば値はfalseとなります。以下の例では条件が「配列の値が0以上」となりすべての配列の値が一致してるのでtrueが返ります。

includes() メソッドについて

includes() は特定の要素が配列に含まれているかどうかを true または false で返すメソッドです。以下の例だと「大阪」が含まれているかどうかなので、trueが返ります。

var test_arr=[1,3,8,9];

var res=test_arr.every((val)=>{
  return val>0;
});

var test_arr=["東京","大阪"];

var res=test_arr2.includes("大阪");

実際のロジック

このevery() と includes()の2つのメソッドを利用することで以下のロジックで2つの配列が一致するかどうかを検証することができます。

let result = ( arrA.length === selectA.length ) && selectA.every( item => arrA.includes( item ) ); 

上記のロジックの結果は true もしくは false で返ってきます。


今回は2つの配列が同じかどうかなので、まずは2つの配列をlengthメソッドで調べます。長さが一致していなければ、falseが返ってきます。

あとは配列の中の要素が一致していればいいのですが、選択した配列の各要素をevery() で走査し、その条件として解答の配列の文字列が含まれているかどうかを includes()メソッドで 調べます。
各要素が含まれていればtrueとなり、すべてtrueとなれば,every()の条件が全て通ったことになりevery()trueが返るので、一致してるという事になります。

JSON.stringify を使った配列の処理

他にも2つの配列が一致してるかどうかの処理方法があります。
その方法がJSON.stringify()を使って、配列をJSONデータに変換することで配列の要素が比較できる方法です。 以下ロジックです。


let result = JSON.stringify( arrA.concat().sort() ) ===JSON.stringify(arrA.concat().sort() );

concatによる複製とsortによる並び替えについて

上記のロジックを見ると分かりますが、JSON.stringify()内で、concat()とsort()の処理を行っています。
sort() に関しては、 JSON形式の文字列に変換する為、並び替えさせないと例え配列に入ってる解答が同じでも一致しません。
例えば[“東京”,”大阪”]が解答で、選択した順番が[“大阪”,”東京”]で配列には同じ内容でも文字列にすると一致しないという事です。

concat()のメソッドは通常は、配列や文字列を連結するメソッドですが、引数を何も指定しないとコピー元の配列をそのまま新しい配列として返すので結果コピーしてるのと同じになります。
では、なぜわざわざ新しい配列を作成しているのかというとsort()元の配列を変更してしまう、いわゆる破壊的メソッドなのでほかの処理に影響が出ないようにconcat()でコピーしているわけです。

ちなみにconcat()ではなく、slice()でも同じ動作が可能です。slice()は引数を指定しなければ、配列の初めから最後までコピーして、配列を生成する事ができるので結果、コピーしたのと同じです。

以下参考サイトです。

ただし 注意点としてJSON.stringify()は変換不可能なオブジェクトが存在するので、要素の値によっては相違を見逃す可能性があります。その場合は最初のarr.lengthevery() を使用した処理をおすすめします。