JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptでオブジェクト配列をgroupプロパティ別にグループ化する方法


問題設定

ここでは、車に関する情報を持つ、次のようなオブジェクトの配列を想定します。各オブジェクトは「group」「name」「code」というプロパティを持ち、groupは配列になっている点が特徴です。

const arr = [
   {
      "group":[],
      "name": "All Makes",
      "code": ""
   },
   {
      "group":["Group A"],
      "name": "BMW",
      "code": "X821"
   },
   {
      "group":["Group B"],
      "name": "Audi",
      "code": "B216"
   },
   {
      "group":["Group B"],
      "name": "Ford",
      "code": "P385"
   },
   {
      "group":["Group B", "Group C"],
      "name": "Mercedes",
      "code": "H801"
   },
   {
      "group":["Group C"],
      "name": "Honda",
      "code": "C213"
   }
];

私たちに求められているのは、このようなオブジェクトの配列を引数として受け取り、各オブジェクトの「group」プロパティの値に基づいて要素をグループ化するJavaScript関数を作成することです。groupプロパティに複数の要素が含まれる場合は、そのオブジェクトを該当するすべてのグループに重複して配置する必要があります。

したがって、上記の配列に対しては、次のような出力が得られることが理想です。

const output = [
   {
      "group": "Group A",
   "cars": [
      {
         name: "BMW",
         code: "X821"
      }
   ]
},
{
   "group": "Group B",
   "cars": [
      {
         name: "Audi",
         code: "B216"
   },
   {
      name: "Ford",
      code: "P385"
   },
   {
      name: "Mercedes",
      code: "H801"
   }
   ]
},
{
   "group": "Group C",
   "cars": [
      {
         name: "Mercedes",
         code: "H801"
      },
      {
         name: "Honda",
         code: "C213"
      }
   ]
   }
];

なお、groupが空配列になっている「All Makes」のようなオブジェクトは、いずれのグループにも属さないため、結果には含まれない点に注意してください。

実装コード

この処理を実現するコードは以下のとおりです。

const arr = [
   {
      "group":[],
      "name": "All Makes",
      "code": ""
   },
   {
      "group":["Group A"],
      "name": "BMW",
      "code": "X821"
   },
   {
      "group":["Group B"],
      "name": "Audi",
      "code": "B216"
   },
   {
      "group":["Group B"],
      "name": "Ford",
      "code": "P385"
   },
   {
      "group":["Group B", "Group C"],
      "name": "Mercedes",
      "code": "H801"
   },
   {
      "group":["Group C"],
      "name": "Honda",
      "code": "C213"
   }
];
const groupTogether = (arr = []) => {
   let res = []
   res = Object.entries(arr.reduce((acc, { group, ...r }) => {
      group.forEach(key => acc[key] = (acc[key] ||
      []).concat({...r}));
      return acc;
   }, {}))
   return res.map(([group, arr]) => ({ group, arr }));
};
console.log(JSON.stringify(groupTogether(arr), undefined, 4));

出力結果

このコードをブラウザのコンソールで実行すると、以下のように表示されます。

[
   {
      "group": "Group A",
      "arr": [
         {
            "name": "BMW",
            "code": "X821"
         }
      ]
   },
 {
   "group": "Group B",
   "arr": [
      {
         "name": "Audi",
         "code": "B216"
      },
      {
         "name": "Ford",
         "code": "P385"
      },
      {
         "name": "Mercedes",
         "code": "H801"
      }
   ]
},
{
   "group": "Group C",
   "arr": [
      {
         "name": "Mercedes",
         "code": "H801"
      },
      {
         "name": "Honda",
         "code": "C213"
      }
   ]
   }
]

コードの仕組み

この実装の中核となっているのはreduceメソッドです。初期値として渡した空のオブジェクト(acc)をアキュムレータに、配列の各要素を順番に処理していきます。

まず、分割代入 { group, ...r } を使って、各オブジェクトからgroupプロパティとそれ以外のデータ(name・codeなど)を分離します。続いて、group配列を forEach でループしながら、グループ名をキーとして車両データを順次連結(concat)していきます。

ここが重要なポイントで、groupプロパティが配列になっているため、1つのオブジェクトを複数のキーに登録できます。そのため、「Group B」と「Group C」の両方に属するMercedesのようなデータも、それぞれのグループに正しく振り分けられるのです。

最後に Object.entries を使ってオブジェクトを[キー, 値]のペアの配列に変換し、mapで { group, arr } という扱いやすい形式へと整形しています。この手法は、車のリストだけでなく、カテゴリやタグによる商品分類など、さまざまな場面で応用できる汎用的なパターンです。

  1. JavaScriptでIDごとにオブジェクトの配列をグループ化する方法

    JavaScriptでオブジェクトの配列をidなどの特定のキーごとにグループ化したい場合、reduce()メソッドを使うと簡潔に実装できます。この記事では、どのプロパティにも対応できる汎用的なgroupBy関数を作成し、実際のサンプルコードとともにその仕組みを詳しく解説します。 reduce()によるグループ化の考え方 reduce()は、配列の各要素を順番に処理しながら、1つの累積値(ここではオブジェクト)を組み立てていくメソッドです。各要素からキーの値を取り出し、その値がまだ結果オブジェクトに存在しなければ新しい配列を作成して、そこへ要素を追加していくことでグループ化を実現します。 サ

  2. JavaScriptでオブジェクトを新しい配列に変換する方法

    JavaScriptでは、オブジェクトのプロパティやネストされたデータを取り出し、扱いやすい形で新しい配列にフォーマットできます。本記事では、学校(school)オブジェクトに含まれる生徒情報を、文字列形式の配列へ変換する実践的なコード例を紹介します。 ポイントとなるテクニック このサンプルでは、以下の2つのJavaScript機能を活用しています。 分割代入(Destructuring assignment):オブジェクトから特定のプロパティを簡潔に取り出す構文です。 for...of ループ:配列内の各要素を順番に処理するために使用します。 コード例 <!DOCTYPE html