多次元配列

配列の配列で表形式・木構造のデータを扱う

配列の中に配列を入れて「表」「オブジェクトリスト」「CSV データ」を扱うトピック。実務で扱うデータはほぼこの形なので、ここから「使える PHP」の入口になる。

このトピックで身につくこと

  • 表 (行 × 列) のデータを PHP の配列で表現できる
  • 行ごと・列ごとの集計ができる
  • ユーザー一覧のような「オブジェクトの配列」を作って検索できる
  • CSV テキストをパースして配列にできる
  • 多次元配列を foreach で走査して処理できる

前提知識の要点

このトピックを始めるのに必要な部分だけをここで圧縮しておく。他のトピックの README を読み返さずに array-multi を単独で開始できる ようにする。

1. 添字配列

$row = [10, 20, 30];
echo $row[0];        // 10
echo count($row);    // 3
▶ 3v4l で実行

2. 連想配列

$user = ['name' => '太郎', 'age' => 20];
echo $user['name'];  // 太郎
▶ 3v4l で実行

3. foreach の 2 つの形

// 値だけ
foreach ($row as $v) { echo $v . "\n"; }

// キーと値
foreach ($user as $k => $v) {
    echo "{$k}: {$v}\n";
}
▶ 3v4l で実行

4. for の入れ子

for ($i = 0; $i < 3; $i++) {
    for ($j = 0; $j < 3; $j++) {
        echo "{$i},{$j} ";
    }
    echo "\n";
}
▶ 3v4l で実行
  • 外側の for が 1 回まわるごとに、内側の for が最後まで回る
  • このトピックではこの「入れ子」を 配列に対して 行う

5. 標準入力で複数行読む

$n = (int)trim(fgets(STDIN));   // 1 行目: 行数
$lines = [];
for ($i = 0; $i < $n; $i++) {
    $lines[] = trim(fgets(STDIN));
}
▶ 3v4l で実行

6. 文字列を分割

$parts = explode(",", "tokyo,osaka,nagoya");
// ["tokyo", "osaka", "nagoya"]
▶ 3v4l で実行
  • CSV を扱う ch11 で使う

ここまで読めば ch01 から始められる。

chapter 一覧

# chapter 内容 学習目標
1 ch01-2d-create/ 2 次元配列を作る [[1,2],[3,4]] の形で配列を入れ子にできる
2 ch02-2d-access/ 要素にアクセス $grid[行][列] で値を取り出せる
3 ch03-2d-modify/ 要素を書き換える $grid[行][列] = 値 で更新できる
4 ch04-2d-foreach/ 入れ子 foreach で全走査 二重 foreach で全要素を扱える
5 ch05-table-print/ 表形式で整形出力 行と列をそろえて表のように表示できる
6 ch06-row-sum/ 各行の合計を出力 行ごとに合計値を求められる
7 ch07-col-sum/ 各列の合計を出力 列ごとに合計値を求められる
8 ch08-assoc-multi/ 連想配列の中に配列 入れ子の連想配列 ($obj['scores'][0]) を扱える
9 ch09-objects-list/ オブジェクトリスト 連想配列の配列 (ユーザー一覧の形) を作れる
10 ch10-find-by-key/ 条件で検索 キーの値が条件に合う要素を探せる
11 ch11-csv-to-2d/ CSV を 2 次元配列に explode() で CSV を 2 次元配列にパースできる
12 ch12-summary/ 多次元配列の総合演習 学生別・科目別の成績データを処理できる

合計 12 chapter / 16 drill / 所要 約 2.5 時間 程度 (ch12 は少し重め)。

進め方

  1. 各 chapter の slide.md を読む (3〜5 分)
  2. drill/ 配下の問題を順番に解く
  3. 採点: php scripts/grade.php topics/array-multi/<chapter>/drill/<drill>/

つまづきポイント

症状 多くの原因
Undefined array key 0 で 2 次元目で死ぬ $grid[行] が配列か確認していない → is_array($grid[$i]) を確認
行と列が逆に出る $grid[列][行] と書いている → 外側の添字が「行」
列の合計が 0 のまま 内側の foreach で外側の合計を加算している → スコープを意識して $colSum[$j] のようにキー指定
CSV をパースして要素数が合わない 行末に改行や空白が残っている → trim() してから explode()
オブジェクトリストで「キーがおかしい」 添字配列 ([$user1, $user2]) と連想配列 (['taro' => $user1]) を混同 → 一覧は前者で持つのが基本
二重 foreach の as $v が読みにくい 外側を as $row、内側を as $cell のように 意味のある名前 にする

関連トピック

トピック 関係
function 多次元配列を引数・戻り値で扱うときに必要
class オブジェクトリストの代わりにクラスでデータを表現できる
exception CSV パース失敗時のエラーを構造的に扱う

トピックを並列で参照する全体地図は TOPICS_INDEX.md にある。

案件 (dojo_map.tsv) での参照

topic_slug    chapter_dir
array-multi   topics/array-multi/ch01-2d-create
array-multi   topics/array-multi/ch04-2d-foreach
array-multi   topics/array-multi/ch11-csv-to-2d
...

slug array-multi で参照可。06-array-multi / array-multi どちらの path でもアクセスできる (シンボリックリンク)。

このレッスンの章

  1. ch01 ch01 — 2 次元配列を作る
  2. ch02 2 次元配列にアクセスする
  3. ch03 ch03 — 2 次元配列の要素を書き換える
  4. ch04 ch04 — 入れ子 foreach で全走査
  5. ch05 ch05 — 表形式で整形出力
  6. ch06 各行の合計を出す
  7. ch07 ch07 — 各列の合計を出力
  8. ch08 ch08 — 連想配列の中に配列を入れる
  9. ch09 ch09 — 連想配列の配列 (オブジェクトリスト)
  10. ch10 ch10 — 条件で検索
  11. ch11 ch11 — 入力 CSV を 2 次元配列にする
  12. ch12 ch12 — 多次元配列の総合演習