# ch12 — 多次元配列の総合演習

Source: https://php-school.pages.dev/topics/array-multi/ch12-summary/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: 多次元配列
Level: L2

Reference (official): https://www.php.net/manual/ja/language.types.array.php

## 本文

# ch12 — 多次元配列の総合演習

## 概要

このトピックの最後は **総合演習**。お題は典型的な「**学生 × 教科の成績データ**」で、標準入力から「1 件 = 名前 + 複数の数値」の形式を読み取り、2 次元配列やオブジェクトリストに組み立て、**行ごとの平均 (各学生の平均) と列ごとの平均 (教科ごとのクラス平均) を使い分ける** ことを目的にする。ここまで (ch01〜ch11) で扱った断片的な技術が、1 つのプログラムとして繋がる経験になる。

ドリル 01 (学生別平均) では **行ごとの集計** が問われる。`array_sum($scores) / count($scores)` のように 1 件のレコードに対して平均を出すパターンで、ch06 (行合計) の発展形。ドリル 02 (教科別クラス平均) では **列ごとの集計** が問われ、ch07 (列合計) の発想を平均に拡張する。同じデータを「縦に見るか / 横に見るか」で答えが変わる、というデータ集計の核心がここで腹落ちする。

実務でも「**売上を月別に見たいのか / 商品別に見たいのか**」「**ユーザー別の合計か / 日別の合計か**」のように **集計軸の切り替え** は常に出てくる。この章でその発想を一度通すと、後で BI ツールやデータ集計スクリプトを書く時の発想の元になる。**標準入力 → パース → 2 次元配列 → 集計 → 出力** という流れを自分の手で一気通貫に書けるようになるのがゴール。

## 学習目標

- 標準入力から「1 件 = 名前 + 複数の数値」のデータを読み、2 次元配列やオブジェクトリストに組み立てられる
- 行ごとの計算 (各学生の平均) と列ごとの計算 (教科ごとの平均) を 1 つのプログラムで使い分けられる
- ここまで (ch01〜ch11) を組み合わせて使える

## 所要時間

スライド 5 分 + ドリル 2 問 = **25 分**

## ドリル

| no | 内容 |
|---|---|
| 01 | 学生 3 人の 3 教科点数を読み、各学生の平均を出力 |
| 02 | 学生 3 人の 3 教科点数を読み、教科ごとのクラス平均を出力 |

## 採点

```bash
php scripts/grade.php topics/array-multi/ch12-summary/drill/01-student-grades/
```

## 関連チャプター

- [`ch06-row-sum`](../ch06-row-sum/) — 行ごとの集計 (ドリル 01 の元になる)
- [`ch07-col-sum`](../ch07-col-sum/) — 列ごとの集計 (ドリル 02 の元になる)
- [`ch11-csv-to-2d`](../ch11-csv-to-2d/) — 標準入力から 2 次元配列を組み立てる前提技術

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 6 / Chapter 12
  目的: ch01〜ch11 までで学んだ多次元配列の操作を組み合わせて、表データの行・列の集計ができるようにする
  扱わない: 関数化 (L7) / クラス (L8)
  読み上げ時間目安: 4 分半〜5 分
-->

# 多次元配列の総合演習

Lesson 6 / Chapter 12

---

## 入力データを「表」として持つ

例として「学生 3 人 × 3 教科の点数」を考える。

入力例:

```
太郎,80,70,90
花子,60,85,75
次郎,90,65,80
```

- 1 行 = 1 人分のデータ
- 名前 + 3 教科の点数

→ 「行 = 学生」「列 = 教科」と見れば、ch01〜ch11 でやってきた表と同じ。

---

## オブジェクトリストに組み立てる

```php
<?php
$students = [];
while (($line = fgets(STDIN)) !== false) {
    $line = rtrim($line, "\n");
    if ($line === "") continue;
    $cols = explode(",", $line);
    $students[] = [
        'name' => $cols[0],
        'scores' => [(int)$cols[1], (int)$cols[2], (int)$cols[3]],
    ];
}
```

- 名前は文字列のまま、点数は整数に変換
- 1 件分を連想配列 (`name` + `scores`) にして配列に追加

---

## 各学生の平均 = 行方向の集計

```php
<?php
foreach ($students as $s) {
    $avg = array_sum($s['scores']) / count($s['scores']);
    echo $s['name'] . ": " . $avg . "\n";
}
```

- 1 件 (1 行) の中で `array_sum / count`
- ch06 (各行の合計) の発展

---

## 教科ごとのクラス平均 = 列方向の集計

```php
<?php
$subjects = count($students[0]['scores']);   // 3
for ($j = 0; $j < $subjects; $j++) {
    $sum = 0;
    foreach ($students as $s) {
        $sum += $s['scores'][$j];
    }
    $avg = $sum / count($students);
    echo $avg . "\n";
}
```

- 外側 = 教科 (列)、内側 = 学生 (行)
- ch07 (各列の合計) の発展

---

## 集計結果を組み合わせると「成績表」になる

- 名前 + 平均 → 個人成績
- 教科ごとの平均 → クラス全体の弱点
- 両方を組み合わせれば、教科別の偏りや個人の得意分野が見える

ここまで来れば、簡易的な集計プログラムは多次元配列だけで十分作れる。

---

## このチャプターでできるようになること

✅ 入力をオブジェクトリストや 2 次元配列に組み立てられる
✅ 行方向 (各人の平均) と列方向 (各教科のクラス平均) を使い分けられる
✅ ch01〜ch11 を組み合わせて 1 つのプログラムにまとめられる

→ ドリルへ
