PHPで配列を扱う際、重複した要素を取り除きたい場面は非常に多くあります。
データのクレンジングや検索結果の整理、あるいはユーザー入力を整理する際に、重複データの処理は避けて通れません。
PHPにはこのような用途に最適な標準関数としてarray_uniqueが用意されています。
この記事では、array_uniqueの基本的な使い方から、実務で直面しやすい注意点までを詳しく解説します。
正しい知識を身につけることで、バグの少ない効率的なコードを記述できるようになります。
まずは、最もシンプルな形での使用例を確認していきましょう。
array_unique関数の基本的な使い方
array_unique関数は、配列から重複する値を削除して、一意な要素のみを持つ新しい配列を返す関数です。
使い方は非常に簡単で、対象となる配列を第一引数に渡すだけで完了します。
// 重複を含む配列の定義
$fruits = ["apple", "banana", "apple", "cherry", "banana"];
// 重複を削除
$unique_fruits = array_unique($fruits);
print_r($unique_fruits);
Array
(
[0] => apple
[1] => banana
[3] => cherry
)
この実行結果を見ると、インデックス「2」と「4」が削除されていることがわかります。
array_uniqueは、同じ値が複数見つかった場合に、最初の要素を優先して残すという特性を持っています。
また、この関数は元の配列を直接書き換えるのではなく、処理結果を戻り値として返します。
そのため、結果を再利用したい場合は必ず変数に代入するようにしましょう。
比較フラグによる挙動の違い
array_uniqueの第二引数には、要素を比較する際のルールを指定するためのフラグを渡すことができます。
デフォルトではSORT_STRINGが指定されており、すべての要素を文字列として比較します。
しかし、数値や異なるデータ型が混在している場合には、意図しない挙動になる可能性があります。
代表的なフラグとその特徴を以下の表にまとめました。
| フラグ名 | 比較方法の概要 |
|---|---|
| SORT_STRING | 各要素を文字列として比較します(デフォルトの挙動です)。 |
| SORT_REGULAR | 型を変換せずに、各要素を通常の比較ルールで判定します。 |
| SORT_NUMERIC | 各要素を数値として比較します。 |
| SORT_LOCALE_STRING | 現在のロケール設定に基づき、文字列として比較します。 |
例えば、数値の「1」と文字列の「”1″」が混在している場合を考えてみましょう。
デフォルトのSORT_STRINGでは、どちらも文字列として扱われるため、一方が削除されます。
一方で、厳密に型を維持したまま比較したい場合には、フラグの選定が重要になります。
$data = [1, "1", 2];
// デフォルト (SORT_STRING)
$result_string = array_unique($data);
// SORT_REGULARを指定
$result_regular = array_unique($data, SORT_REGULAR);
print_r($result_string);
print_r($result_regular);
// SORT_STRINGの結果
Array ( [0] => 1 [2] => 2 )
// SORT_REGULARの結果
Array ( [0] => 1 [1] => 1 [2] => 2 )
データの性質に応じて適切なフラグを選択することが、正確な重複削除の鍵となります。
インデックス(添え字)の扱いに注意
array_uniqueを使用する際に最も注意すべき点は、削除後のキー(インデックス)の挙動です。
先ほどの出力結果でも確認した通り、重複した要素のキーは取り除かれ、残った要素のキーは維持されます。
つまり、配列のキーが不連続な状態になってしまうのです。
不連続なキーのままfor文などでループ処理を行うと、未定義のインデックスを参照してエラーが発生するリスクがあります。
これを解決するためには、array_values関数を組み合わせてキーを振り直すのが一般的です。
$input = ["a", "b", "a"];
$unique = array_unique($input);
// キーを0から振り直す
$reindexed = array_values($unique);
print_r($reindexed);
Array
(
[0] => a
[1] => b
)
このようにarray_valuesを適用することで、キーが「0, 1, 2…」と綺麗に整列されます。
特にJSON形式でAPIのレスポンスを返す場合、キーが欠けていると配列ではなくオブジェクトとして解釈されることがあります。
フロントエンド側の処理で予期せぬ挙動を防ぐためにも、キーの振り直しは習慣化しておくと良いでしょう。
多次元配列における重複削除のテクニック
残念ながら、array_uniqueは多次元配列を直接扱うことができません。
例えば、連想配列の中にさらに配列が入っているような構造では、単純にこの関数を呼び出しても期待した結果は得られません。
多次元配列から重複を除去したい場合は、カスタム関数を作成するか、他の関数を組み合わせる必要があります。
一つの簡便な手法として、各要素を一時的にJSON文字列に変換してから重複を削除する方法があります。
$users = [
["id" => 1, "name" => "田中"],
["id" => 2, "name" => "鈴木"],
["id" => 1, "name" => "田中"], // 重複
];
// 一度シリアライズして重複削除し、元に戻す
$unique_users = array_map("json_decode", array_unique(array_map("json_encode", $users), SORT_STRING));
// 多次元配列の場合は、連想配列としての構造を維持するために追加処理が必要な場合もあります
print_r($unique_users);
ただし、この方法はデータのシリアライズとデシリアライズを繰り返すため、計算コストが高くなります。
大規模なデータを扱うプロジェクトでは、foreachループを利用して特定のキー(今回の例なら”id”)を基準に手動でフィルタリングを行うのが現実的です。
また、PHPのコレクションライブラリやフレームワーク(Laravelなど)を使用している場合は、より高度な一意化メソッドが提供されていることもあります。
大量のデータを扱う場合のパフォーマンス最適化
数万件規模の大きな配列を処理する場合、array_uniqueの実行速度がパフォーマンスのボトルネックになることがあります。
実は、PHPにおいて「値の重複を消す」という目的を達成するための、より高速な代替手法が存在します。
それがarray_flip関数を二回利用するテクニックです。
$large_array = ["apple", "banana", "apple", "cherry", "banana" /* 非常に長い配列 */];
// array_flipを二回実行する高速化手法
$fast_unique = array_flip(array_flip($large_array));
print_r($fast_unique);
array_flipは配列の「キー」と「値」を入れ替える関数です。
PHPの配列は「同じキーを重複して持てない」という性質を持っているため、値をキーに変換した瞬間に重複が自動的に消滅します。
この手法は内部アルゴリズムの都合上、array_uniqueよりも数倍から数十倍高速に動作することがあります。
ただし、このテクニックが使えるのは、配列の値が「文字列」または「整数」である場合に限られます。
浮動小数点数やオブジェクトを含む場合は、エラーや意図しない型変換が発生するため注意してください。
用途が限定される分、条件を満たす場合には非常に強力な最適化手段となります。
PHP 8.x以降の最新環境での考慮点
近年のPHP(8.1や8.2、8.3以降)では、言語の仕様がより厳格化されています。
array_unique自体に劇的な変更はありませんが、周辺の関数や型システムの強化により、開発者が意識すべきポイントが増えています。
例えば、数値形式の文字列の扱い(”10″と10の比較など)は、PHPのバージョンアップとともに洗練されてきました。
古いPHPバージョンで書かれたコードを最新環境へ移行する際は、フラグ指定なしのarray_uniqueがどのように動作するかを再テストすべきです。
特にSORT_REGULARを使用する場合、オブジェクトの比較ルールが厳密であることを理解しておく必要があります。
オブジェクト同士を比較する際、それらが同じクラスのインスタンスであり、かつプロパティの値が一致しているかどうかがチェックされます。
こうした細かい挙動を把握しておくことで、将来的なバージョンアップにも耐えられる堅牢なコードを記述できます。
まとめ
PHPのarray_unique関数は、シンプルながらも非常に強力なツールです。
基本的な使い方をマスターするだけでなく、第二引数の比較フラグを適切に使い分けることで、多様なデータ構造に対応できます。
また、削除後にキーが不連続になるという特性を理解し、必要に応じてarray_valuesで整理することも重要です。
多次元配列や大規模なデータセットを扱う場合には、標準関数の組み合わせやarray_flipによる高速化など、一歩踏み込んだ工夫が求められます。
実務においては、単に重複を消すだけでなく「どのようなルールで一意とするか」を明確に定義することが大切です。
今回紹介したテクニックを活用して、ぜひ効率的でメンテナンス性の高いPHPプログラムを実装してください。
