tag:crieit.net,2005:https://crieit.net/tags/%E3%83%8D%E3%82%B9%E3%83%88%E3%81%97%E3%81%9F%E9%85%8D%E5%88%97/feed 「ネストした配列」の記事 - Crieit Crieitでタグ「ネストした配列」に投稿された最近の記事 2022-07-14T23:39:50+09:00 https://crieit.net/tags/%E3%83%8D%E3%82%B9%E3%83%88%E3%81%97%E3%81%9F%E9%85%8D%E5%88%97/feed tag:crieit.net,2005:PublicArticle/18239 2022-07-14T23:39:50+09:00 2022-07-14T23:39:50+09:00 https://crieit.net/posts/extract-array-of-diff-exclude-duplicated-between-two-arraies-by-javascript-20220715 JavaScript で互いにオブジェクトを要素に持つ配列2つを比較して、重複していない要素のみを取り出す <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>JavaScript で、互いにオブジェクトを要素に持つ配列2つを比較して、重複していない要素のみを取り出す処理を試みたのでメモしておきます。</p> <h2 id="前提"><a href="#%E5%89%8D%E6%8F%90">前提</a></h2> <p>前提として、次のような2つの配列があったとします。</p> <ul> <li>互いにオブジェクトを要素として持つ配列</li> <li>配列2は配列1の子集合(サブセット)</li> </ul> <p>この2つの配列を比較して、配列1の中から<strong>配列2に含まれない要素のみ</strong>の配列を作りたい、と考えました。</p> <p>想定する最終結果も併せて付記しておきます。</p> <h3 id="配列1"><a href="#%E9%85%8D%E5%88%971">配列1</a></h3> <pre><code class="json">[ { "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" } ] </code></pre> <h3 id="配列2"><a href="#%E9%85%8D%E5%88%972">配列2</a></h3> <pre><code class="json">[ { "value": "value-0", "label": "Château d'If" }, { "value": "value-1", "label": "Le Comte de Monte-Cristo" }, { "value": "value-2", "label": "Alexandre Dumas" } ] </code></pre> <h3 id="得たい配列"><a href="#%E5%BE%97%E3%81%9F%E3%81%84%E9%85%8D%E5%88%97">得たい配列</a></h3> <pre><code class="json">[ { "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" } ] </code></pre> <p>「2つの配列で重複した要素を除去した配列を生成する」というのはいくつか記事を見かけました。</p> <p>しかし、それらは1次元配列のサンプルばかりだった上に、今回はさらに「要素の中の <code>label</code>キー の値で比較したい」という内容だったので、さらにハードルが上がりました。</p> <h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.nxworld.net/js-array-filter-snippets.html">JavaScript:filter()を使って配列内の重複要素を削除・取得したり、2つの配列から共通要素を取得する方法 - NxWorld</a></li> </ul> <p>最終的にはこちらのコードをベースにして作りました。</p> <p>サンプルは以下。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://arm-band.github.io/test-l-enfer-de-chateau-d-if/">Home - L'enfer de Chateau d'If</a></li> </ul> <pre><code class="javascript">// 配列 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); }); </code></pre> <p>ざっくりこのような処理で想定していた結果を得られました。</p> <h2 id="余談"><a href="#%E4%BD%99%E8%AB%87">余談</a></h2> <p>何故このようなことをしようかと思ったかというと、 <a target="_blank" rel="nofollow noopener" href="https://react-select.com/home">React Select</a> で <code>defaultCalue</code> で指定した選択済みの項目が選択候補にも上がってしまっていたので、除外しようとしたためでした。</p> <p>が、そもそも React Select 側は選択済み項目を除外する機能を元々持っていたので上述の処理は不要ということが分かったため、今回のコードは未使用となりました。</p> <p>ちなみに、この機能が働かなかった原因は API で取得した 値から 上述のような <code>label</code> と <code>value</code> のオブジェクトを生成するループ処理の際に、 <code>value</code> に ID の数値を振り方を間違えていたため、 React Select から「異なる値」として認識されてしまっていたためでした。</p> <p>また、仮に今回の処理をかけたとしても、初期表示では上手く選択済み項目が除外されますが、選択済み項目を削除した場合は選択可能な項目として再度選択肢に復活させる必要があるため、かなり手間がかかることが想定されたためオミットしていたと思います。</p> <p>……本当、 React Select 側に標準搭載されていて良かったです。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="本題"><a href="#%E6%9C%AC%E9%A1%8C">本題</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.nxworld.net/js-array-filter-snippets.html">JavaScript:filter()を使って配列内の重複要素を削除・取得したり、2つの配列から共通要素を取得する方法 - NxWorld</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.dkrk-blog.net/javascript/duplicate_an_array">配列同士で重複する値があるか確認する | grgr-dkrkのブログ</a></li> </ul> <h3 id="label のみの配列を作る"><a href="#label+%E3%81%AE%E3%81%BF%E3%81%AE%E9%85%8D%E5%88%97%E3%82%92%E4%BD%9C%E3%82%8B">label のみの配列を作る</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/tsu_eng/items/57f9d3919bf175188033">JavaScriptで連想配列から特定のキーだけ抽出 - Qiita</a></li> </ul> <h3 id="配列操作"><a href="#%E9%85%8D%E5%88%97%E6%93%8D%E4%BD%9C">配列操作</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/takeharu/items/d75f96f81ff83680013f">JavaScriptの配列の使い方まとめ。要素の追加,結合,取得,削除。 - Qiita</a></li> </ul> <h3 id="JSON のフォーマット"><a href="#JSON+%E3%81%AE%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88">JSON のフォーマット</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/unsoluble_sugar/items/7df08527215ea92831a6">JSON.stringifyの出力結果を整形して可読性を向上させる - Qiita</a></li> </ul> arm-band