JavaScript Tips | 配列ユーティリティ:表データ生成

JavaScript JavaScript
スポンサーリンク

テーマの整理:「表データ生成」とは何か

ここで扱う「表データ生成」は、配列から「表として扱いやすい形」を作るためのユーティリティです。 業務だと、次のような場面でよく出てきます。

画面に一覧テーブルを表示したい。 Excel や CSV に出すための「行と列」を作りたい。 API から来た生データを、「表」としてきれいに並べ直したい。

つまり、「バラバラな配列データ」を、 ヘッダー(列定義)と行(レコード)を持つ“表構造”に変換するのが、ここでのテーマです。

基本コンセプト:ヘッダー定義+行データで「表」を作る

表データの基本形を決める

まず、「表」をコードでどう表現するかを決めます。 初心者にも分かりやすく、かつ業務で使いやすい形はこんな感じです。

const table = {
  columns: [
    { key: "id",    label: "ID" },
    { key: "name",  label: "氏名" },
    { key: "email", label: "メールアドレス" },
  ],
  rows: [
    { id: 1, name: "Alice", email: "alice@example.com" },
    { id: 2, name: "Bob",   email: "bob@example.com" },
  ],
};
JavaScript

ここでのポイントは、

columns が「表の列定義」(どのキーをどんな名前で表示するか)。 rows が「実際のデータ」(オブジェクト配列)。

という構造になっていることです。 この形にしておくと、画面表示・CSV 変換・Excel 行変換などにそのまま使えます。

ユーティリティ 1:オブジェクト配列から表データを生成する

実装:createTableFromObjects

まずは、「オブジェクト配列から表データを作る」基本ユーティリティです。

function createTableFromObjects(objects, columnDefs) {
  if (!Array.isArray(objects) || objects.length === 0) {
    return { columns: [], rows: [] };
  }

  const columns =
    Array.isArray(columnDefs) && columnDefs.length > 0
      ? columnDefs
      : Object.keys(objects[0]).map((key) => ({
          key,
          label: key,
        }));

  const rows = objects.map((obj) => ({ ...obj }));

  return { columns, rows };
}
JavaScript

重要なポイントをかみ砕いて説明します。

objects は「元になるオブジェクト配列」です。 columnDefs が渡されていれば、それを列定義として使います。 columnDefs がない場合は、最初のオブジェクトのキーから列定義を自動生成します(label はとりあえずキー名)。 rows は「元のオブジェクトをそのままコピーしたもの」で、表の行になります。

これで、「ただのオブジェクト配列」が「列定義付きの表データ」に変わります。

例題:ユーザー一覧から表データを作る

const users = [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob",   email: "bob@example.com" },
];

const table = createTableFromObjects(users);

console.log("columns:", table.columns);
console.log("rows:", table.rows);
JavaScript

出力イメージはこうなります。

columns: [
  { key: "id",    label: "id" },
  { key: "name",  label: "name" },
  { key: "email", label: "email" },
]
rows: [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob",   email: "bob@example.com" },
]
JavaScript

このまま画面のテーブルコンポーネントに渡したり、CSV や Excel に変換したりできます。

ユーティリティ 2:列定義をカスタマイズして表を作る

列順・表示名・フォーマットを指定する

業務では、「列の順番」「表示名」「フォーマット」が仕様で決められていることが多いです。 そこで、列定義を明示的に渡せるようにしておきます。

列定義の例はこんな感じです。

const userColumns = [
  { key: "id",    label: "ユーザーID" },
  { key: "name",  label: "氏名" },
  { key: "email", label: "メールアドレス" },
];
JavaScript

これを createTableFromObjects に渡します。

const users = [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob",   email: "bob@example.com" },
];

const table = createTableFromObjects(users, userColumns);

console.log("columns:", table.columns);
console.log("rows:", table.rows);
JavaScript

出力イメージはこうなります。

columns: [
  { key: "id",    label: "ユーザーID" },
  { key: "name",  label: "氏名" },
  { key: "email", label: "メールアドレス" },
]
rows: [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob",   email: "bob@example.com" },
]
JavaScript

ここでの重要ポイントは、

内部のキー(id, name, email)と、画面や Excel に出すときの表示名(日本語)が分離されている。 列順も columnDefs の順番で決まるので、仕様に合わせやすい。

というところです。

ユーティリティ 3:表データから「表示用セル配列」を生成する

テーブルコンポーネントに渡しやすい形を作る

画面にテーブルを出すときは、 「列定義」と「行ごとのセル配列」があると扱いやすいです。

そこで、表データから「セル配列」を作るユーティリティを用意します。

function tableToCellMatrix(table) {
  const { columns, rows } = table;

  if (!Array.isArray(columns) || !Array.isArray(rows)) {
    return [];
  }

  return rows.map((row) =>
    columns.map((col) => row[col.key] ?? "")
  );
}
JavaScript

ここでのポイントは、

columns の順番に従って、各行のセルを並べている。 値が undefined や null のときは空文字にしている。 戻り値は「行の配列」で、各行は「セルの配列」になっている。

というところです。

例題:表データからセル配列を作る

const users = [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob",   email: "bob@example.com" },
];

const userColumns = [
  { key: "id",    label: "ユーザーID" },
  { key: "name",  label: "氏名" },
  { key: "email", label: "メールアドレス" },
];

const table = createTableFromObjects(users, userColumns);
const cells = tableToCellMatrix(table);

console.log("cells:", cells);
JavaScript

出力イメージはこうなります。

cells: [
  [1, "Alice", "alice@example.com"],
  [2, "Bob",   "bob@example.com"],
]
JavaScript

この形は、HTML テーブル・Excel 行・CSV などにそのまま使える「表の中身」です。

ユーティリティ 4:集計結果から「表」を生成する

シナリオ

売上データの配列から、 「日別売上」「担当者別売上」などの集計表を作りたい。

集計+表生成の例

まず、売上データを用意します。

const sales = [
  { date: "2024-07-01", user: "Alice", amount: 100 },
  { date: "2024-07-01", user: "Bob",   amount: 200 },
  { date: "2024-07-02", user: "Alice", amount: 150 },
];
JavaScript

日別売上を集計します。

function aggregateSalesByDate(sales) {
  const map = new Map();

  sales.forEach((s) => {
    const prev = map.get(s.date) ?? 0;
    map.set(s.date, prev + s.amount);
  });

  return Array.from(map.entries()).map(([date, total]) => ({
    date,
    total,
  }));
}

const daily = aggregateSalesByDate(sales);
JavaScript

集計結果を表データにします。

const dailyColumns = [
  { key: "date",  label: "日付" },
  { key: "total", label: "売上合計" },
];

const dailyTable = createTableFromObjects(daily, dailyColumns);
const dailyCells = tableToCellMatrix(dailyTable);

console.log("columns:", dailyTable.columns);
console.log("rows:", dailyTable.rows);
console.log("cells:", dailyCells);
JavaScript

ここでの重要ポイントは、

生データ(sales)から集計結果(daily)を作り、 それを「列定義付きの表」にしている。 さらにセル配列まで作っているので、画面表示・Excel・CSV などにすぐ使える。

という流れになっていることです。

表データ生成ユーティリティで意識してほしい重要ポイント

「列定義」を中心に設計する

表データ生成の肝は、列定義(columns)をちゃんと持つことです。

どのキーを表に出すか。 どんな表示名にするか。 どんな順番で並べるか。

これを columns に閉じ込めておくと、

画面表示、CSV、Excel、PDF など、 どの出力先でも「同じ列定義」を使い回せます。

初心者向けには、まずは「key と label だけ」のシンプルな列定義から始めて、 必要になったら「フォーマッタ」「幅」「ソート設定」などを追加していくイメージを持つとよいです。

「行データ」はできるだけ素直に保つ

rows は「ただのオブジェクト配列」です。 ここに余計な情報(表示用の文字列や HTML)を混ぜ始めると、 表データがごちゃごちゃしてきます。

だからこそ、

rows は「生の値」を持つ。 表示用の加工は、必要なら別の層(コンポーネントやフォーマッタ)で行う。

というスタンスでいると、 表データ生成ユーティリティがシンプルで保守しやすくなります。

手を動かして「表データ生成」の感覚をつかむ

次のコードを実行して、

オブジェクト配列 → 表データ → セル配列 という流れを体感してみてください。

function createTableFromObjects(objects, columnDefs) {
  if (!Array.isArray(objects) || objects.length === 0) {
    return { columns: [], rows: [] };
  }

  const columns =
    Array.isArray(columnDefs) && columnDefs.length > 0
      ? columnDefs
      : Object.keys(objects[0]).map((key) => ({
          key,
          label: key,
        }));

  const rows = objects.map((obj) => ({ ...obj }));

  return { columns, rows };
}

function tableToCellMatrix(table) {
  const { columns, rows } = table;

  if (!Array.isArray(columns) || !Array.isArray(rows)) {
    return [];
  }

  return rows.map((row) =>
    columns.map((col) => row[col.key] ?? "")
  );
}

function demo() {
  const users = [
    { id: 1, name: "Alice", email: "alice@example.com" },
    { id: 2, name: "Bob",   email: "bob@example.com" },
  ];

  const userColumns = [
    { key: "id",    label: "ユーザーID" },
    { key: "name",  label: "氏名" },
    { key: "email", label: "メールアドレス" },
  ];

  const table = createTableFromObjects(users, userColumns);
  const cells = tableToCellMatrix(table);

  console.log("columns:", table.columns);
  console.log("rows:", table.rows);
  console.log("cells:", cells);
}

demo();
JavaScript

まとめ:表データ生成ユーティリティで「配列を“表”として扱う」

「表データ生成」は、 「ただの配列を、“列定義付きの表”として扱えるようにするためのユーティリティ」です。

プロジェクトに例えば次のような形で置いておくイメージです。

export function createTableFromObjects(objects, columnDefs) { ... }
export function tableToCellMatrix(table) { ... }
JavaScript

そして、

一覧画面、レポート、Excel/CSV 出力など、 「表っぽいもの」を扱うところでは、必ずこの表データ生成を通す。

こう決めておくと、 配列まわりのコードが「ただの寄せ集め」ではなく、 ちゃんとした「表としての構造」を持つようになっていきます。

配列を“表”として扱えるようになると、 業務データの見通しが一気によくなるので、ここはぜひ押さえておきたいところです。

タイトルとURLをコピーしました