2つの配列を比べて「片方にしかない値」や「両方に共通する値」を取り出したいことがあります。PHP では array_diff() で差分を、array_intersect() で共通部分を簡単に求められます。この記事では、これらの基本的な使い方と、キーも比較する array_diff_assoc() などの仲間、つまずきやすいポイントまでをコード例つきで解説します。
目次
array_diff() で差分(引き算)を求める
array_diff() は、第1引数の配列から、ほかの配列に含まれる値を取り除いた結果を返します。「A から B にある値を引く」イメージです。元の配列は変更せず、新しい配列を返します。
<?php
$all = ['apple', 'banana', 'orange', 'grape'];
$ordered = ['banana', 'grape'];
// $all から $ordered にある値を取り除く
$remaining = array_diff($all, $ordered);
print_r($remaining);
// Array
// (
// [0] => apple
// [2] => orange
// )
結果の配列では、元のキー(上の例では 0 と 2)がそのまま保持される点に注意してください。連番に振り直したいときは、後述の array_values() を使います。第3引数以降にも配列を渡せ、それらすべてに含まれない値だけが残ります。
array_intersect() で共通部分を求める
array_intersect() は逆に、すべての配列に共通して含まれる値だけを返します。「AND(かつ)」の関係で、複数の配列に共通する要素を抜き出したいときに使います。
<?php
$userRoles = ['editor', 'author', 'subscriber'];
$allowedRoles = ['administrator', 'editor', 'author'];
// 両方に含まれる値だけを取り出す
$matched = array_intersect($userRoles, $allowedRoles);
print_r($matched);
// Array
// (
// [0] => editor
// [1] => author
// )
こちらも第1引数のキーが保持されます。ユーザーが持つ権限のうち、許可リストに含まれるものだけを抜き出す、といった用途で役立ちます。
値の比較方法と仲間の関数
array_diff() と array_intersect() は「値」だけを比較します。比較は文字列に変換して行われるため、数値の 1 と文字列の "1" は同じとみなされます。キーも合わせて比較したい場合や、キーだけで比較したい場合は、用途に応じた仲間の関数が用意されています。
| 関数 | 比較するもの |
|---|---|
array_diff() / array_intersect() | 値のみ |
array_diff_assoc() / array_intersect_assoc() | キーと値の両方 |
array_diff_key() / array_intersect_key() | キーのみ |
たとえば連想配列で「キーと値のペアが一致するもの」を比べたいときは _assoc 版を使います。次の例で挙動の違いを確認できます。
<?php
$a = ['name' => 'Sato', 'age' => 30, 'city' => 'Tokyo'];
$b = ['name' => 'Sato', 'age' => 25, 'city' => 'Tokyo'];
// キーと値の両方で比較。age だけ値が違うので差分になる
$diff = array_diff_assoc($a, $b);
print_r($diff);
// Array
// (
// [age] => 30
// )
実践例:追加・削除された項目を見つける
array_diff() をうまく使うと、変更前と変更後の2つのリストを比べて「追加されたもの」と「削除されたもの」を同時に求められます。引く順番を入れ替えるのがポイントです。
<?php
$before = ['html', 'css', 'php'];
$after = ['html', 'css', 'javascript'];
// after にあって before に無い → 追加された
$added = array_values(array_diff($after, $before));
// before にあって after に無い → 削除された
$removed = array_values(array_diff($before, $after));
print_r($added); // Array ( [0] => javascript )
print_r($removed); // Array ( [0] => php )
ここでは array_values() で結果のキーを 0 から振り直しています。タグの編集差分や、設定項目の変更検出などに応用できます。
思った結果にならないとき
キーが連番に戻らない
これらの関数は元の配列のキーを保持するため、結果は [0, 2, 5] のような飛び飛びのキーになることがあります。foreach で回すだけなら問題ありませんが、0 から順番のキーが欲しいときや json_encode() で配列として出力したいときは、array_values() でキーを振り直してください。
オブジェクトや配列を含むと警告が出る
array_diff() や array_intersect() は値を文字列に変換して比較します。そのため、要素にオブジェクトや配列が含まれていると「配列を文字列に変換できない」といった警告が出て、正しく比較できません。多次元配列を比較したい場合は、比較したい値を取り出してから渡すか、用途に合わせて自分でループを書く必要があります。
まとめ
array_diff() と array_intersect() は、2つ以上の配列を比べるときの基本となる関数です。
array_diff()は第1引数からほかの配列にある値を取り除く(差分)array_intersect()はすべての配列に共通する値を返す(共通部分)- キーも比較したいなら
_assoc版、キーだけなら_key版を使う - 引く順番を入れ替えれば「追加」「削除」を同時に求められる
- 結果のキーは保持されるので、必要に応じて
array_values()で振り直す
リスト同士の比較は自分でループを書きがちですが、これらの関数を使えば1行で書けてミスも減ります。差分や共通部分を求めたくなったら、まずこの2つを思い出してみてください。