array_unique() で小ハマリ
PHPの関数 array_unique() で小ハマリしたのでメモ。
array_unique() は、配列から重複する要素を削除する関数。
たとえば、こんなプログラム。
$list = array_unique($list);
for ($cnt = 0; $cnt < count($list); $cnt++)
{
print($list[$cnt] . "\n");
}
このプログラムは、「A」「B」「A」「C」という配列から、array_unique() によって、重複する「A」の余分な要素を取り除き、「A」「B」「C」という配列にするプログラムである。
このプログラムにおける、期待する実行結果は、こうである。
B
C
ところが、実際にプログラムを実行すると、この様に出力される。
B
最後の要素「C」が出力されない。
なぜだ。
実行結果だけを見ると、count($list) の値が「2」であるように見える。
確認してみよう。
$list = array_unique($list);
print(sprintf("===%d===\n", count($list))); // ★追加★
for ($cnt = 0; $cnt < count($list); $cnt++)
{
print($list[$cnt] . "\n");
}
実行してみると…
A
B
count($list) の値は「3」なのに、最後の要素が出力されない。
なぜだ。
var_dump() で配列の内容を一覧してみよう。
$list を初期化した後と、array_unique() を通した後に var_dump() を入れてみる。
var_dump($list); // ★追加★
$list = array_unique($list);
var_dump($list); // ★追加★
for ($cnt = 0; $cnt < count($list); $cnt++)
{
print($list[$cnt] . "\n");
}
実行してみると…
[0]=>
string(1) "A"
[1]=>
string(1) "B"
[2]=>
string(1) "A"
[3]=>
string(1) "C"
}
array(3) {
[0]=>
string(1) "A"
[1]=>
string(1) "B"
[3]=>
string(1) "C"
}
A
B
なるほど、array_unique() を通した後は、重複している要素番号[2]が抜けて、 [0][1][3] と飛んだ状態で格納されている。
要素数(つまり count($list))は「3」なので、for は [0][1][2] でループするのだけれど、最後の要素の添え字は [3] だから出力されないのか。
おそらく、[2] は null なのだな。
確認してみよう。
$list = array_unique($list);
for ($cnt = 0; $cnt < count($list); $cnt++)
{
if ($list[$cnt] == null) // ★追加★
{
print("NULL!\n");
}
print($list[$cnt] . "\n");
}
実行してみる。
B
NULL!
では、array_unique() を通した後の配列を正しくループさせるにはどうしたらいいのだろう。
sort() を通して配列を並べ替えたらどうだろうか。
$list = array_unique($list);
sort($list); // ★追加★
for ($cnt = 0; $cnt < count($list); $cnt++)
{
print($list[$cnt] . "\n");
}
できた!
B
C
しかし、これでは配列がソートされてしまう。ソートしたくない場合はどうしたらいいのだろうか。
array_系の関数をざっと見てみる... これか、array_merge() を使用して、1個の配列だけをマージしてみたらどうか。
やってみよう。
$list = array_unique($list);
$list = array_merge($list); // ★追加★
for ($cnt = 0; $cnt < count($list); $cnt++)
{
print($list[$cnt] . "\n");
}
できた!
B
C
もっといいやり方があるような気がするのだが、とりあえず、これでヨシとしよう。
なかなか奥が深い。