【javascript】2つの連想配列を比較し、重複するものを返す
目次
javascriptの連想配列を比較し、重複するものがないか、調べたい
どうも、高島です。
javascriptで2つの配列があります。 両方とも存在するデータを取り出すには、どうすればいいでしょうか?
普通の配列を比較するサンプルは、ネット上に結構あるのですが、連想配列の例があまり無かったので、記事を書きました。
早速ですが、filterの中でfilterを呼べば、可能です。
const ary1 = [ {"keyno":"A1","room":"101"}, {"keyno":"A1","room":"102"}, {"keyno":"B1","room":"201"}, {"keyno":"C1","room":"301"}, {"keyno":"D1","room":"401"}, ]; const ary2 = [ {"keyno":"A1","room":"101"}, {"keyno":"C3","room":"301"}, {"keyno":"D1","room":"401"}, {"keyno":"E1","room":"501"}, ]; // 重複有り var reList = ary1.filter(ary1row=>ary2.filter( ary2row=> ary2row.keyno === ary1row.keyno && ary2row.room === ary1row.room).length > 0); console.log("両方とも存在するデータ"); console.log(reList);
結果はこうです。
両方とも存在するデータ [ { keyno: 'A1', room: '101' }, { keyno: 'D1', room: '401' } ]
filter内はどんな動きなのか?
実際はどんな処理がされているのでしょうか? console.logを埋め込んで確認してみます。
// 内部の動作を確認してみる ary1.filter(ary1row=>{ console.log("ary1row.room=" + ary1row.room); ary2.filter( ary2row=>{ console.log(" ary2row.room=" + ary2row.room); }) });
結果はこうなりました。
ary1row.room=101 ary2row.room=101 ary2row.room=301 ary2row.room=401 ary2row.room=501 ary1row.room=102 ary2row.room=101 ary2row.room=301 ary2row.room=401 ary2row.room=501 ary1row.room=201 ary2row.room=101 ary2row.room=301 ary2row.room=401 ary2row.room=501 ary1row.room=301 ary2row.room=101 ary2row.room=301 ary2row.room=401 ary2row.room=501 ary1row.room=401 ary2row.room=101 ary2row.room=301 ary2row.room=401 ary2row.room=501
ary1をループして、さらにその中でary2をループしていることがわかります。 filterを使えば、ループを書かなくて済む、というわけです。
冒頭の重複を取り出す処理に話を戻します。
ary2.filter関数が、ary1rowとary2rowを比較し、一致する行を返してくれます。 この部分ですね。
ary2.filter( ary2row=> ary2row.keyno === ary1row.keyno && ary2row.room === ary1row.room)
ary2.filterは、比較条件がtrueならば、データを返します。 もしfalseなら何も返しません。
データを返ってきたか否かは、lengthで判断します。
もうちょっとわかりやすく、returnを省略せずに、lengthでのtrue/false判定を分離して書いてみます。
var reList = ary1.filter(ary1row=>ary2.filter(
ary2row=>
ary2row.keyno === ary1row.keyno &&
ary2row.room === ary1row.room).length > 0);
↓↓↓↓↓↓
var reList = ary1.filter(ary1row=>{ var reAry2row = ary2.filter( ary2row=>{ return (ary2row.keyno === ary1row.keyno && ary2row.room === ary1row.room) }); return reAry2row.length > 0 ; });
ary1rowとマッチしたreAry2row が存在すれば、length > 0 、ですのでtrueで返します。 ary1.filter()はtrueとなったary1rowをreListに返します。
こうして重複したデータのみが reListにセットされます。
2つの配列を比較し、重複しないものを返す
では、ary1に存在するがary2に存在しないデータは?
これは簡単です。結果が0件のものですね。 length === 0 に変えます。
// 重複しない reList = ary1.filter(ary1row=>ary2.filter( ary2row=> ary2row.keyno === ary1row.keyno && ary2row.room === ary1row.room).length === 0); console.log("ary1に存在するがary2に存在しないデータ"); console.log(reList);
ary1に存在するがary2に存在しないデータ [ { keyno: 'A1', room: '102' }, { keyno: 'B1', room: '201' }, { keyno: 'C1', room: '301' } ]
(おまけ)自分自身の配列内で重複を取り出す
これまでは、異なる配列同士を比較しましたが、 今度は自分自身と比較すればいいです。
const ary1 = [ {"keyno":"A1","room":"101"}, {"keyno":"A1","room":"102"}, {"keyno":"B1","room":"201"}, {"keyno":"C1","room":"301"}, {"keyno":"A1","room":"101"}, {"keyno":"C1","room":"301"}, {"keyno":"D1","room":"401"}, ]; // 重複有り var reList = ary1.filter((ary1row,ary1idx,selfary)=>selfary.filter( ary2row=> ary2row.keyno === ary1row.keyno && ary2row.room === ary1row.room).length > 1); console.log("重複するデータ"); console.log(reList);
重複するデータ [ { keyno: 'A1', room: '101' }, { keyno: 'C1', room: '301' }, { keyno: 'A1', room: '101' }, { keyno: 'C1', room: '301' } ]
filter() はcallback関数を引数にとります。 このcallback関数の第3引数は自分自身の配列です。 それと比較すればいいです。
まとめ
filter内でfilterを呼び、そこで比較すれば、二重ループを書く必要はなくなります。
最初にfilter見たときは訳わかりませんでしたが、理解するとスッキリ書けます。
欠点といえば、読むには慣れが必要なことでしょうか。
人が書いたものは、正直ちょっとわかりにくいことが多いです。
var reList = ary1.filter((x,y,z)=>z.filter(
w=>
w.keyno === x.keyno &&
w.room === x.room).length > 1);
アロー関数は、こんな感じで略した変数名で書くことが多いので、変数名からは内容が推測できませんし、returnを省略して書かれると、初心者はコードが読めずに苦しんだりします。
もう慣れるしかないんでしょうけどね。