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

JavaScriptで2次元配列をカテゴリ別にグループ化されたオブジェクトの配列へ変換する方法


問題の概要

ここでは、色や果物に関するデータを格納した次のような2次元配列があると仮定します。

const data = [
    ['orange', 'fruit'],
    ['red', 'color'],
    ['green', 'color'],
    ['orange', 'color'],
    ['banana', 'fruit'],
    ['blue', 'color'],
    ['lemon', 'fruit'],
    ['mango', 'fruit'],
    ['lemon', 'color'],
];

この配列を引数として受け取り、要素(果物や色)をそれぞれのカテゴリごとにグループ化した配列を返す関数を作成する必要があります。

今回の例では「fruit」と「color」の2つのカテゴリしか存在しないため、出力として期待されるのは、次のような2つのオブジェクトからなる配列です。

[
    {
        group: 'fruit',
        value: ['orange', 'banana', 'lemon', 'mango']
    },
    {
        group: 'color',
        value: ['red', 'green', 'orange', 'blue', 'lemon']
    }
]

注意: この例では2つのカテゴリしかありませんが、求められているのは2つだけでなく、動的な数のカテゴリにも対応できる汎用的な解決策です。

解決のアプローチ

それでは、この問題に対する解決策を考えてみましょう。ここではArray.prototype.reduce()メソッドを使用します。各サブ配列を処理する際に、同じ名前のグループがすでに存在するかどうかを確認し、次のように処理を分岐させます。

  • グループが既に存在する場合:新しい値をそのオブジェクトのvalueプロパティに追加する
  • グループが存在しない場合:そのグループ用の新しいオブジェクトを作成し、結果の配列に追加する

コード例

const data = [
    ['orange', 'fruit'],
    ['red', 'color'],
    ['green', 'color'],
    ['orange', 'color'],
    ['banana', 'fruit'],
    ['blue', 'color'],
    ['lemon', 'fruit'],
    ['mango', 'fruit'],
    ['lemon', 'color'],
];
const groupData = arr => {
    return arr.reduce((acc, val) => {
        const [value, groupName] = val;
        const groupIndex = acc.findIndex(el => el?.group === groupName);
        if(groupIndex !== -1){
            acc[groupIndex].value.push(value);
        }else{
            acc.push({
                group: groupName,
                value: [value]
            });
        }
        return acc;
    }, []);
};
console.log(groupData(data));

出力

コンソールには次のように出力されます。

[
    { group: 'fruit', value: [ 'orange', 'banana', 'lemon', 'mango' ] },
    {
        group: 'color',
        value: [ 'red', 'green', 'orange', 'blue', 'lemon' ]
    }
]

コードの解説

  • reduce()の初期値:空の配列[]を初期アキュムレータとして指定し、最終的にこの配列へグループ化されたオブジェクトが蓄積されます。
  • 分割代入const [value, groupName] = val;により、サブ配列の先頭要素を値として、2番目の要素をグループ名として取り出しています。
  • findIndex()による判定el?.group === groupNameで既存グループの有無をチェックします。オプショナルチェイニング(?.)を使うことで、要素がnullやundefinedの場合でもエラーにならず安全に動作します。
  • パフォーマンスに関する補足:findIndex()は各要素ごとに線形探索を行うため、大量のデータを扱う場合は、あらかじめMapなどでグループ名とインデックスの対応を管理すると、全体をO(n)で処理でき効率的になります。
  1. JavaScriptでIDごとにオブジェクトの配列をグループ化する方法

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

  2. JavaScriptでオブジェクトを含む「配列の配列」をループ処理する方法

    JavaScriptでオブジェクトを含む多次元配列をループするには?JavaScriptでは、オブジェクトを含む配列の配列(入れ子構造の配列)をループ処理する際、forEach()メソッドをネストして使用し、さらにfor...inループで各オブジェクトのプロパティにアクセスするのが一般的な方法です。以下に、具体的な実装例を紹介します。コード例<!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name=viewport content=width=device