ユアスク by みんなシステムズ

MENU

【実装例あり】PHPで配列内の重複した値を削除する方法 -これで配列データの重複も怖くない!-

2023/03/27

【PHP】WBC、配列、連想配列、多次元配列、重複データの削除に関する内容

こんにちは!

今回はPHPでよく使用される配列の重複データを削除する方法を解説します。

配列内で重複しているものだけを残したい!と考えたとき思ったように重複削除できないと思ったことはありませんか?

今回は配列、連想配列、多次元配列に関し重複を削除する方法を解説します。

少し長いですが最後までお付き合いいただければ幸いです。

「配列 重複 削除」と検索すると。。

「配列 重複 削除」で検索するとと検索すると真っ先に出てくるのはarray_uniqueだと思います。

array_uniqueとは配列から重複した値を削除する

これは配列、連想配列の記載がありますが、実は盲点があるのでその盲点を理解いていただいた上で実際、私の使用したロジックをご説明できればと思います。

ちなみに多次元配列は想定していないと記載があるのでこのことも知っておきましょう

注意array_unique() は、 多次元配列での使用を想定したものではないことに注意しましょう。

引用はこちらから

最後に多次元配列での重複削除も行う方法もご紹介させていただきます。

array_uniqueの盲点とは?

配列とarray_unique

array_unique対応ができる連想配列は下記のようなもの

<?php
$wbcMemberArray = [
	'member' => 'ダルビッシュ 有','戸郷 翔征','大勢','大谷 翔平','大勢'
];


echo '<pre>';
print_r($wbcMemberArray);

echo '----------------------------';
// 重複削除処理した方
$arrayUnique = array_unique($wbcMemberArray); 
echo '<pre>';
print_r($arrayUnique);
?>

デバッグ使用すると下記のように表示されます。

// デバッグ画面
// 重複削除していない配列の中身
Array
(
    [0] => ダルビッシュ 有
    [1] => 戸郷 翔征
    [2] => 大勢
    [3] => 大谷 翔平
    [4] => 大勢
)
----------------------------
// 重複削除した配列の中身
Array
(
    [0] => ダルビッシュ 有
    [1] => 戸郷 翔征
    [2] => 大勢
    [3] => 大谷 翔平
)

この$wbcMemberArrayの配列だと重複している【大勢】が消えています。

array_uniqueはしっかり機能していますね。

では次の連想配列ではどうでしょうか?

連想配列とarray_unique

連想配列とは、キーと値をセットで保持することができる配列のこと。

array('キー' => '値', 'キー' => '値', 'キー' => '値',,,,,);
<?php
$wbcMemberArray = array('ダルビッシュ' => '36歳', '大谷' => '28歳', '松井' => '27歳');

echo '<pre>';
print_r($wbcMemberArray);

// デバッグ
Array
(
    [ダルビッシュ] => 36歳
    [大谷] => 28歳
    [松井] => 27歳
)
?>

連想配列であっても、下記の場合はPHPによって上書きされてしまいます。

<?php
① keyが被っている場合
$wbcMemberArray = array('ダルビッシュ' => '36歳', '大谷' => '28歳', '松井' => '27歳', '大谷' => '20歳');

// ①のデバッグ
Array
(
    [ダルビッシュ] => 36歳
    [大谷] => 20歳 ※年齢が上書きされている
    [松井] => 27歳
)

② keyとvalueが被っている場合
$wbcMemberArray = array('ダルビッシュ' => '36歳', '大谷' => '28歳', '大谷' => '28歳');

// ②のデバッグ
Array
(
    [ダルビッシュ] => 36歳
    [大谷] => 28歳 ※2人目の大谷選手消えちゃいましたね。
)

?>

この結果を見ると、連想配列では「key」が被っている時点で重複が削除されてしまうようですね。

では、③keyは違うけれど、valueが被っている場合はどうでしょう。

<?php
// ③keyは違うけれど、valueが被っている場合
$wbcMemberArray = array('ダルビッシュ' => '36歳', '大谷' => '28歳', '松井' => '25歳', 'ヌートバー' => '25歳');

// ③のデバッグ
Array
(
    [ダルビッシュ] => 36歳
    [大谷] => 28歳
    [松井] => 25歳
    [ヌートバー] => 25歳
)
?>

③の場合は、なにも削除されずにずべてのデータが残っています。

では、これにarray_uniqueつけて見ましょう。

④ keyは違うけれど、valueが被っている場合にarray_uniqueを使用する

<?php
④ keyは違うけれど、valueが被っている場合にarray_uniqueを使用する

$wbcMemberArray = array('ダルビッシュ' => '36歳', '大谷' => '28歳', '松井' => '25歳', 'ヌートバー' => '25歳');
$arrayUnique = array_unique($wbcMemberArray); 

echo '<pre>';
print_r($arrayUnique);

// デバッグ
Array
(
    [ダルビッシュ] => 36歳
    [大谷] => 28歳
    [松井] => 25歳
)

お!まさかのヌートバー選手が消えました😭

このことから、どうやら連想配列でarray_uniqueを使用するとvalueで重複しているか判断しているようですね。

ちょっと複雑だったので、連想配列だけで一旦まとめます。

連想配列での重複に関するまとめ

結果keyの重複valueの重複
PHPによって同じkeyのものは上書きされるありなし
PHPによって同じkeyのものは上書きされるありあり
PHPによって連想配列は変化しないなしあり
array_uniqueにより同じvalueでは先に出てきたデータが優先されるなしあり

重複削除したいからと言って、連想配列に何も考えずにarray_uniqueを使用すると痛い目にあいそうですね。

多次元連想配列の重複削除

<?php
$wbcMembers = array(
	array('id' => 1,
		  'name' => "ダルビッシュ",
		  'team' => "パドレス"),
	array('id' => 2,
	      'name' => "大谷",
		  'team' => "エンゼルス"),
	array('id' => 3,
	      'name' => "ダルビッシュ",
		  'team' => "パドレス"),
);

?>
// デバッグ処理
// array_uniqueの処理なし 
echo '<pre>';
print_r($wbcMembers);
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => ダルビッシュ
            [team] => パドレス
        )

    [1] => Array
        (
            [id] => 2
            [name] => 大谷
            [team] => エンゼルス
        )

    [2] => Array
        (
            [id] => 3
            [name] => ダルビッシュ
            [team] => パドレス
        )
)
// デバッグ処理
// array_uniqueの処理あり
$arrayUnique = array_unique($wbcMembers); 
echo '<pre>';
print_r($arrayUnique);

// デバッグ処理の結果
// array_uniqueの処理あり
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => ダルビッシュ
            [team] => パドレス
        )

)

実務でよくあるのはDBからデータを取得した際、idなどのユニークキーがあっても多次元配列でarray_uniqueを使用すると変な挙動を示すという点が意外と盲点なのです。

どうすれば、idに関係なく[ダルビッシュ]と[大谷]のデータを重複なく取れるのでしょうか?🤔🤔🤔

目標とするほしい配列はこちらです。

Array
(
    [0] => Array
        (
            [name] => ダルビッシュ
            [team] => パドレス
        )

    [1] => Array
        (
            [name] => 大谷
            [team] => エンゼルス
        )
)

他の関数を使用し対処する方法【実装例あり】

ここで使用するのがarray_pushin_arrayという関数。

array_push は一つ以上の要素を配列の最後に追加する

in_array は配列に値があるかチェックする

では、この2つの関数で実際に実装して見ましょう!

<?php

$wbcMembers = array(
	array('id' => 1,
		  'name' => "ダルビッシュ",
		  'team' => "パドレス"),
	array('id' => 2,
	      'name' => "大谷",
		  'team' => "エンゼルス"),
	array('id' => 3,
	      'name' => "ダルビッシュ",
		  'team' => "パドレス"),
);

$uniqueMemberArray = [];
$checkDataArray = [];

foreach($wbcMembers as $wbcMember) {
	
	$checkData = $wbcMember['name'] . $wbcMember['team'];
	if(!in_array($checkData, $checkDataArray, true)) {
		$array = [
			'name' => $wbcMember['name'],
			'team' => $wbcMember['team'],
		];
		array_push($uniqueMemberArray, $array);	
	}
	
	array_push($checkDataArray, $checkData);

}

// デバッグ作業
echo '<pre>';
print_r($uniqueMemberArray);
// デバッグ内容
Array
(
    [0] => Array
        (
            [name] => ダルビッシュ
            [team] => パドレス
        )

    [1] => Array
        (
            [name] => 大谷
            [team] => エンゼルス
        )
)

やった〜!!欲しかった情報がちゃんと配列に入ってます!!🎉🥳

【解説】

まず、準備として空の配列を準備します。

  • 1つ目は重複削除後の選手データを入れるもの->$uniqueMemberArray = [];
  • 2つ目はin_arrayでチェックするもの->$checkDataArray = [];
$uniqueMemberArray = [];
$checkDataArray = [];

次に、下記のように重複するものが$uniqueMemberArrayに入らないように文字列を作成し、その文字列を$checkDataArrayにpushします。

// 例)「ダルビッシュパドレス」という文字列を作成
$checkData = $wbcMember['name'] . $wbcMember['team'];

この$checkDataは毎回、先ほど準備した$checkDataArrayに挿入されていきます。

//最後までforeachが回るとこんな感じの配列になります
// 例) $checkDataArray = [ダルビッシュパドレス, 大谷エンゼルス, ダルビッシュパドレス];
array_push($checkDataArray, $checkData);

今回のforeachの流れ

1周目には「ダルビッシュパドレス」が$checkDataArrayに格納されていないので、!in_array($checkData, $checkDataArray, true)trueになるので$uniqueMemberArrayにダルビッシュ選手の情報が格納されます。

2週目の「大谷エンゼルス」はまだ、$checkDataArrayに格納されていないので、!in_array($checkData, $checkDataArray, true))trueになり、$uniqueMemberArrayに大谷選手の情報が格納される。

3周目は、$checkDataArray に「ダルビッシュパドレス」が格納されるので、同じ文字列がくると次は!in_array($checkData, $checkDataArray, true)falseになってしまうので、$uniqueMemberArrayに「ダルビッシュパドレス」が格納されることはありません。

といった流れです。

全体のまとめ

配列はarray_uniqueでOK

連想配列はarray_uniqueで半分OK半分NG

多次元配列はarray_uniqueはNG

最後に

少し難しいかもしれませんが、結構応用が効く内容なので覚えといて損はないかなっと思います。

こんな難しい方法じゃなくて、もっと簡単な方法があるかもしれません。

その際はご一報いただければ助かります。

ここまで読んでいただきありがとうございました😊