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

JavaScriptで2D表形式データをオブジェクトの配列に変換する方法

JavaScriptでは、CSVファイルの読み込み結果やスプレッドシートから取得したデータなど、配列の中に配列が入った「2次元配列」で表形式データを扱う場面が多くあります。本記事では、このような2次元配列を、特定のキー(氏名)ごとにグループ化したオブジェクトの配列へ変換する方法を解説します。

課題の内容

まず、次のような配列の配列を例に考えてみましょう。

const arr = [
    ["Ashley","2017-01-10",80],
    ["Ashley","2017-02-10",75],
    ["Ashley","2017-03-10",85],
    ["Clara","2017-01-10",90],
    ["Clara","2017-02-10",82]
];

各サブ配列は「氏名」「日付」「数値」の3つの要素で構成されています。求められているのは、この配列を引数として受け取り、氏名(サブ配列の先頭要素)が同じ行を1つのオブジェクトにまとめ、それらを要素とする新しい配列を返す関数です。

期待される出力

出力の配列には氏名ごとに1つのオブジェクトが対応し、日付がプロパティ名、数値がその値として格納されます。イメージは以下の通りです。

const output = [
    {"name":"Ashley", "2017-01-10":80, "2017-02-10":75, "2017-03-10":85},
    {"name":"Clara", "2017-01-10":90, "2017-02-10":82}
];

実装例:reduce()を使ったグループ化

以下のコードでは、Array.prototype.reduce()を活用し、クロージャで保持したハッシュマップによって既出の氏名を追跡しながらグループ化を行っています。

const arr = [
    ["Ashley","2017-01-10",80],
    ["Ashley","2017-02-10",75],
    ["Ashley","2017-03-10",85],
    ["Clara","2017-01-10",90],
    ["Clara","2017-02-10",82]
];
const groupArray = (arr = []) => {
    let grouped = [];
    grouped = arr.reduce(function (hash) {
        return function (r, a) {
            if (!hash[a[0]]) {
                hash[a[0]] = { name: a[0] };
                r.push(hash[a[0]]);
            }
            hash[a[0]][a[1]] = a[2];
            return r;
        };
    }(Object.create(null)), []);
    return grouped;
};
console.log(groupArray(arr));

コードのポイント

  • ハッシュマップによる重複チェック:Object.create(null)で生成したプレーンなオブジェクトをハッシュマップとして使うことで、プロトタイプチェーン上のプロパティとの衝突を避けられます。
  • 初回検出時のみオブジェクトを生成:氏名(a[0])が未登録の場合に限り、name プロパティを持つ新しいオブジェクトを作成し、結果配列へ push します。
  • 日付をキーに値を追記:同じ氏名の行が複数現れても、日付(a[1])をキーとして数値(a[2])を順に代入することで、1つのオブジェクトへ統合されます。

実行結果

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

[
    { name: 'Ashley',
      '2017-01-10': 80,
      '2017-02-10': 75,
      '2017-03-10': 85 },
    { name: 'Clara',
      '2017-01-10': 90,
      '2017-02-10': 82 }
]

別解:Mapを使ったシンプルな書き方

reduce()を使わず、Map と for...of ループを組み合わせると、より読みやすいコードになります。

const groupArray = (arr = []) => {
    const map = new Map();
    for (const [name, date, value] of arr) {
        if (!map.has(name)) {
            map.set(name, { name });
        }
        map.get(name)[date] = value;
    }
    return [...map.values()];
};
console.log(groupArray(arr));

Map は挿入順序を保持するため、元の配列での登場順どおりにオブジェクトが並ぶ点もメリットです。用途や好みに応じて、両者の実装を使い分けるとよいでしょう。

  1. JavaScriptのlengthプロパティで配列オブジェクトの長さを取得する方法

    JavaScriptにおけるlengthプロパティとはJavaScriptのlengthプロパティは、文字列や配列などのオブジェクトが持つ要素数(サイズ)を返すために使用されます。配列の場合は格納されている要素の個数、文字列の場合は文字数を取得できます。ここでは、文字列と配列オブジェクトの長さをlengthプロパティで取得するサンプルコードを紹介します。サンプルコード以下の例では、ボタンをクリックすると配列の長さが画面に表示される仕組みを実装しています。<!DOCTYPE html> <html lang="ja"> <head> <

  2. JavaScriptで辞書(連想配列)をオブジェクトのリストに変換する方法

    JavaScriptでは、キーと値のペアを持つ「辞書」のようなオブジェクトを、Object.values()メソッドを使うことで簡単にオブジェクトの配列(リスト)へ変換できます。以下に具体的なサンプルコードを示します。 サンプルコード <!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name=viewport content=width=device-width, initial-scale=1.0 /> <title>Document&