経緯
JavaScript で、互いにオブジェクトを要素に持つ配列2つを比較して、重複していない要素のみを取り出す処理を試みたのでメモしておきます。
前提
前提として、次のような2つの配列があったとします。
- 互いにオブジェクトを要素として持つ配列
- 配列2は配列1の子集合(サブセット)
この2つの配列を比較して、配列1の中から配列2に含まれない要素のみの配列を作りたい、と考えました。
想定する最終結果も併せて付記しておきます。
配列1
[
{
"value": "value-0",
"label": "Château d'If"
},
{
"value": "value-1",
"label": "Marseille"
},
{
"value": "value-2",
"label": "France"
},
{
"value": "value-3",
"label": "Le Comte de Monte-Cristo"
},
{
"value": "value-4",
"label": "Alexandre Dumas"
},
{
"value": "value-5",
"label": "Rhino"
},
{
"value": "value-6",
"label": "prison"
},
{
"value": "value-7",
"label": "François I"
},
{
"value": "value-8",
"label": "Jean-Baptiste Kléber"
}
]
配列2
[
{
"value": "value-0",
"label": "Château d'If"
},
{
"value": "value-1",
"label": "Le Comte de Monte-Cristo"
},
{
"value": "value-2",
"label": "Alexandre Dumas"
}
]
得たい配列
[
{
"value": "value-1",
"label": "Marseille"
},
{
"value": "value-2",
"label": "France"
},
{
"value": "value-5",
"label": "Rhino"
},
{
"value": "value-6",
"label": "prison"
},
{
"value": "value-7",
"label": "François I"
},
{
"value": "value-8",
"label": "Jean-Baptiste Kléber"
}
]
「2つの配列で重複した要素を除去した配列を生成する」というのはいくつか記事を見かけました。
しかし、それらは1次元配列のサンプルばかりだった上に、今回はさらに「要素の中の label
キー の値で比較したい」という内容だったので、さらにハードルが上がりました。
コード
最終的にはこちらのコードをベースにして作りました。
サンプルは以下。
// 配列
const Ar1 = [
// 略
];
const Ar2 = [
// 略
];
// 重複要素を除去した配列を返す関数
const getArraysDiff = (array1, array2) => {
// 引数の各々の配列から label のみの配列を生成
const array1LabelArray = array1.map((itm) => {
return itm.label;
});
const array2LabelArray = array2.map((itm) => {
return itm.label;
});
// label のみの配列で比較
const arr1 = [...new Set(array1LabelArray)];
const arr2 = [...new Set(array2LabelArray)];
return [...arr1, ...arr2].filter((val) => {
return !arr1.includes(val) || !arr2.includes(val);
});
};
// 上述関数で重複除去した label の配列を得る
const ChateuDiff = getArraysDiff(Ar1, Ar2);
// filter メソッドで、元配列 から該当する label が存在する要素を除去する
const enferChateuDiff = Ar1.filter((item) => {
return ChateuDiff.includes(item.label);
});
ざっくりこのような処理で想定していた結果を得られました。
余談
何故このようなことをしようかと思ったかというと、 React Select で defaultCalue
で指定した選択済みの項目が選択候補にも上がってしまっていたので、除外しようとしたためでした。
が、そもそも React Select 側は選択済み項目を除外する機能を元々持っていたので上述の処理は不要ということが分かったため、今回のコードは未使用となりました。
ちなみに、この機能が働かなかった原因は API で取得した 値から 上述のような label
と value
のオブジェクトを生成するループ処理の際に、 value
に ID の数値を振り方を間違えていたため、 React Select から「異なる値」として認識されてしまっていたためでした。
また、仮に今回の処理をかけたとしても、初期表示では上手く選択済み項目が除外されますが、選択済み項目を削除した場合は選択可能な項目として再度選択肢に復活させる必要があるため、かなり手間がかかることが想定されたためオミットしていたと思います。
……本当、 React Select 側に標準搭載されていて良かったです。
参考
本題
- JavaScript:filter()を使って配列内の重複要素を削除・取得したり、2つの配列から共通要素を取得する方法 – NxWorld
- 配列同士で重複する値があるか確認する | grgr-dkrkのブログ