PHPを使っていると、配列の差分を取りたいという場面によく遭遇します。
通常の配列であれば、array_diff()を使って簡単に差分を抽出できるのですが、連想配列だとうまく行かないことが分かりました。そこで、array_udiffを使って、連想配列を抽出してみます。
目次
とりあえずコード
function associative_array_diff ($keys, $array_1, ...$array_n) {
foreach ($array_n as $array_i) {
$result = array_udiff($array_1, $array_i, function ($a, $b) use ($keys) {
foreach ($keys as $key) {
$cmp = spaceship_operator($a[$key], $b[$key]); //PHP7未満の場合
$cmp = $a[$key] <=> $b[$key]; //PHP7以上の場合
if ($cmp) return $cmp;
}
return $cmp;
});
}
}
function spaceship_operator ($a, $b) {
if ($a === $b) {
return 0;
} elseif ($a < $b) {
return -1;
} else {
return 1;
}
}
連想配列を抽出する関数は、associative_array_diffです。こちらのQiitaの記事を参考にさせていただきました。ポイントは、array_udiffを使うという点です。
array_udiff
array_udiffは、データの比較にコールバック関数を用いて、配列の差を計算する関数です。(公式ドキュメントより)
ポイントになるのはコールバック関数です。返り値を以下のように設定することが義務付けられています。
- 最初の引数 < 2番目の引数 の場合:負の値
- 最初の引数 = 2番目の引数の場合:0
- 最初の引数 > 2番目の引数 : 正の値
このようなコールバック関数を用意することによって、連想配列の任意のキー(複数も可能)を比較して、差分を抽出することができるのです。
PHP7以降では、宇宙船演算子(<=>)によって、上記の3パターンを簡単に返すことが出来ます。一方でPHP7未満のバージョンだと、上のソースコードのspaceship_operatorのような関数を用意する必要があります。
使ってみるとこんな感じ
$arr_1 = [
0 => [
'id' => 1,
'name' => 'AAA',
'sex' => 'M',
],
1 => [
'id' => 2,
'name' => 'BBB',
'sex' => 'M',
],
2 => [
'id' => 3,
'name' => 'CCC',
'sex' => 'W',
],
];
$arr_2 = [
0 => [
'id' => 1,
'name' => 'DDD',
'sex' => 'M',
],
1 => [
'id' => 2,
'name' => 'BBB',
'sex' => 'M',
],
];
associative_array_diff(['id', 'name'], $arr_1, $arr_2);
// 出力:['id' => 3,'name' => 'CCC','sex' => 'W',]
今回は、idとnameの両方が一致したものは落とす(つまり、少なくともどちらかが違っていたら抽出する)ようにしました。
このように、連想配列であってもキーを指定して差分を抽出することが出来ました。










