- 2つの配列を比べて「片方にしかない要素」を探すときは
array_diff($全体, $除外分)を使う - 二重ループやフラグ変数を書く必要がなくなり、1行で未提出者や未選択データを抽出できる
- 抽出後の配列は元の添字(インデックス)が飛び飛びになるため、連番にしたいときは
array_values()で整える
1. 今日のお題とゴール
クラスの全メンバー配列から、宿題を提出済みのメンバー配列を引き算して、「まだ提出していない人」の一覧と人数を表示する処理を作ります。
- 全メンバー
['田中', '佐藤', '鈴木', '高橋']から提出済み['田中', '鈴木']を除外する - 残った未提出者の人数をカウントして表示する
- 添字を振り直して「1人目、2人目…」と連番で名前を出力する
// 期待する出力例
未提出は 2 名です
1人目: 佐藤
2人目: 高橋
2. ❌ やりがちなNGコード vs ⭕ コピペで動く正解コード
<?php
$allMembers = ['田中', '佐藤', '鈴木', '高橋'];
$submitted = ['田中', '鈴木'];
$unsubmitted = [];
foreach ($allMembers as $member) {
$isSubmitted = false;
foreach ($submitted as $done) {
if ($member === $done) $isSubmitted = true; // 二重ループで1人ずつ照合
}
if (!$isSubmitted) $unsubmitted[] = $member;
}
ループの中にループを入れる「二重ループ」とフラグ変数($isSubmitted)で探そうとすると、コードが深くなって読みづらくなります。メンバー数が増えるほど比較回数も膨れ上がり、バグが紛れ込む原因になります。
<?php
declare(strict_types=1);
// 全メンバーと、宿題の提出済みメンバー
$allMembers = ['田中', '佐藤', '鈴木', '高橋'];
$submitted = ['田中', '鈴木'];
// 1. 全メンバーから提出済みを引き算して「未提出者」だけを抽出する
$diff = array_diff($allMembers, $submitted);
// 2. 飛び飛びになった添字(1, 3)を 0, 1 の連番に振り直す
$unsubmitted = array_values($diff);
// 3. 未提出の人数と一覧を出力する
$count = count($unsubmitted);
echo "未提出は {$count} 名です\n";
foreach ($unsubmitted as $index => $name) {
$number = $index + 1;
echo "{$number}人目: {$name}\n";
}
3. ここだけ押さえる!3つのポイント
array_diff($配列A, $配列B) は「AからBを引き算」する第1引数の配列をベースにして、第2引数の配列に含まれている値を除いた残りを返します。引数の順番を逆にすると結果が変わってしまうため、「基準となる全体リスト」を必ず最初に渡しましょう。
array_values() で連番に整えるarray_diff() の結果は [1 => '佐藤', 3 => '高橋'] のように元の配列のインデックス番号を維持します。$index + 1 で順番を表示したり $unsubmitted[0] で先頭を取り出したりする場合は、array_values() で添字を 0, 1... に振り直すと安全です。
array_intersect()差分ではなく「両方の配列に入っている人(提出済みのメンバー)」を抽出したいときは array_intersect() を使います。「違いを探す=array_diff」「共通を探す=array_intersect」とペアで覚えておくと実務で重宝します。
4. 1分ミニチャレンジ
🚀 手を動かしてみよう
正解コード9行目の array_diff($allMembers, $submitted) を array_intersect($allMembers, $submitted) に書き換えて実行してみましょう。今度は両方の配列に共通する「提出済みのメンバー(田中、鈴木)」の2名だけが抽出されることを確認できます。