JavaScriptで複数の配列内の要素を比較してすべてに存在する要素を抜き出す、ということが必要になったことがありました。
次のように3つの配列があった場合に、
- 配列A:[1, 2, 3, 4, 5]
- 配列B:[1, 2, 4, 5]
- 配列C:[2, 3, 4]
配列A・B・Cのすべてに存在する要素を抽出する。
- 取得したい内容:[2, 4]
配列全てに対してFor文でループして比較すれば実現できそうではあるのですが、比較したい配列が4個、5個・・・・と多くなるとその分複雑になり、ちょっとイマイチ感が出てきます。
何かサンプルコードがないかをググってみましたが使えそうなのものがあまり出てこなかったため、今回はサンプルJavaScriptコードを合わせて、複数配列を比較し全てに存在する要素を取得する方法をご紹介します。
もっとうまい方法があるはずと感覚的には思うのですが、やり方がわからなかったためロジックを自作してみました。
配列内の要素は文字または数値という前提です。要素がオブジェクトの場合はこれから紹介するロジックでは実現できないと思いますので、ご注意ください。
共通する要素を抽出する際の考え方
複数の配列内の要素を比較するため、次のようなロジックで行えば実現できるかと思い、試してみました。
ここでは配列1・配列2・配列3の3つを比較する場合を例として、次のようなものを考えました
比較したい配列を用意する
まず、比較したい配列を用意します。
//比較したい配列
var arr1 = ['a', 'b', 'c', 'd', 'e'];
var arr2 = ['a', 'b', 'd', 'e'];
var arr3 = ['b', 'c', 'd'];
変数arr1、arr2、arr3にそれぞれの内容が入っているとします。
最終的には、すべての配列に存在する、bとdを取得します。
各配列内の要素を1つにまとめる
比較したい配列の要素を、1つの配列にまとめます。
//配列を1つにまとめる
var arrs = [arr1, arr2, arr3];
配列内に配列が入っている結果となります。
変数arrsは後の処理で使用します。
次に、各配列の要素を1つにまとめます。
//配列要素を1つにまとめる
var arrsCon = arr1.concat(arr2).concat(arr3);
JavaScriptのconcat関数で配列を1つにまとめた結果は次のようになります。
["a", "b", "c", "d", "e", "a", "b", "d", "e", "b", "c", "d"]
この状態だと配列1、配列2、配列3の各要素が全て入っているため、要素が重複しています。そこで、filter関数を用いて重複を取り除きます。
//配列内の重複を削除
var arrsUnique = arrs.filter(function (x, i, self) {
return self.indexOf(x) === i;
});
console.log(arrsUnique);
重複を取り除いた結果、次のようになります。
["a", "b", "c", "d", "e"]
配列1・配列2・配列3のどれかに含まれる要素がこれで抽出できました。
比較したい配列すべてに含まれるものを抽出する
配列1・配列2・配列3のどれかに含まれる要素は抽出できましたので、これに対して各配列を比較し、すべてに存在するものを抽出します。
//比較したい配列(arr1,arr2,arr3)のすべてに含まれるもののみ抽出
var resultArr = arrsUnique.filter(function(val) {
var flg = true;
arrs.forEach(function(compArr, i) {
flg = (compArr.indexOf(val) !== -1) && flg;
});
return flg;
});
console.log(resultArr);
forEachの部分では、要素が各配列に存在するかをindexOf関数で比較をしています。結果をflg変数に入れていますので、すべての配列で存在すればtrueとなり、一部の配列には存在しない場合はfalseが設定されます。
結果は次のようになります。想定通り、配列1・配列2・配列3のすべてに含まれるbとdが取得できました。
["b", "d"]
JavaScriptのサンプルコード
上記の考え方を元に作成したコードが次の通りです。
//比較したい配列
var arr1 = ['a', 'b', 'c', 'd', 'e'];
var arr2 = ['a', 'b', 'd', 'e'];
var arr3 = ['b', 'c', 'd'];
//配列を1つにまとめる
var arrs = [arr1, arr2, arr3];
var resultArr = arrs.reduce(function(previousValue, currentValue, index, array) {
//比較したい配列をreduceで結合して1つにまとめる
return previousValue.concat(currentValue);
}).filter(function (x, i, self) {
//重複を削除
return self.indexOf(x) === i;
}).filter(function(val) {
//比較したい配列(arr1,arr2,arr3)のすべてに含まれるもののみ抽出
var flg = true;
arrs.forEach(function(compArr) {
flg = (compArr.indexOf(val) !== -1) && flg;
});
return flg;
});
console.log(resultArr);
JavaScriptで配列操作を行う場合、for文ではなくreduce関数、forEach関数、filter関数を使用するとすっきりしますね。
変数arrsに比較したい配列を設定してあげれば処理が動くため、配列が増えた場合もロジックを増やすことなくすべての配列に含まれる要素を抽出して抜き出すことができると思います。
まとめ
今回は、JavaScriptで複数の配列のすべてに含まれる要素を抜き出す処理をソースコードを添えてご紹介しました。
ここで紹介したコードはやりたいことを実現する一例ですが、参考になれば幸いです。
おそらくはreduceのみで実現できるもっと別の方法があると思いますがわかりませんでした。わかる方はぜひ教えてください!