肉とビールとパンケーキ by @sotarok

少し大人になった「肉とご飯と甘いもの」

おもむろにarray_unique的な話とか


PHPには、Pythonのsetみたいなものがなくて、添字配列も連想配列も集合も全部配列として扱わなきゃいけないから、まあ、その分怪しげな関数が山ほど用意されてて、おきまりのパターンでいくと、配列でなんかデータ保持しておいて、array_* って感じの関数使えばなんか適当に何とかなるって場合が多い。

ああ、そんなわけで、集合的なものを作りたい場合、がーーーーっと配列つくって、最後にarray_uniqueしてやるみたいな方法があったりするよね、って話。

例えば、以下のようなかんじ。

<?php

$result = array();
foreach (range(1,100) as $i) {
    $result[] = mt_rand(1, 10);
}
var_dump(array_unique($result));

ああ、もうこんなコードは適当な例であって、意味は全然ないんだけど、とにかくどっかから情報を集めてきて、それを一意にしたいとか。まあ、Pythonでsetつかえば(r


でも、array_unique ってやつは、

っていう感じの素敵関数なんだけど。


フレームワーク内でこういうコードがあったらほげほげ!みたいな話があったんだけど、Ethnaにはあんまりつかわれてなくて(2件だけ使われてる場所があるけど)、似たようなことを実現するコードがある。
これ、多分昔いちいさんが書いたやつだと思うんだけど。
コード読んでたときに、最初はなにしてんだこれ、と思ったけど後からなんとなくああ、そうか、これは array_unique だ! と思ったので。


というわけで、こういう書き方もあるよね、くらいの話ですが。

<?php

$result = array();
foreach (range(1,100) as $i) {
    $result[mt_rand(1, 10)] = 0;
}
var_dump(array_keys($result));

最後に取りたい値はキーにして、最後にarray_keys ってやつですね。

速度とか

ちなみに程度の話。まともに検証してないけど。
まあ速度っていうか最後にarray_uniqueするのは配列を拡張しまくるので、それが遅いのかもね。

% for ((i = 0; i < 5 ; i += 1)) do; time php unique_array_keys.php; done;
php unique_array_keys.php  0.30s user 3.82s system 99% cpu 4.129 total
php unique_array_keys.php  0.25s user 3.80s system 99% cpu 4.051 total
php unique_array_keys.php  0.30s user 3.78s system 99% cpu 4.087 total
php unique_array_keys.php  0.29s user 3.74s system 100% cpu 4.024 total
php unique_array_keys.php  0.34s user 3.79s system 97% cpu 4.215 total

に対して、

% for ((i = 0; i < 5 ; i += 1)) do; time php unique_array_unique.php ; done; 
php unique_array_unique.php  2.43s user 4.21s system 99% cpu 6.657 total
php unique_array_unique.php  2.43s user 4.18s system 99% cpu 6.616 total
php unique_array_unique.php  2.50s user 4.14s system 99% cpu 6.676 total
php unique_array_unique.php  2.36s user 4.23s system 99% cpu 6.608 total
php unique_array_unique.php  2.56s user 4.23s system 99% cpu 6.803 total


あと、配列につっこむだけつっこんでサイズ広げたりしないから、省メモリなんじゃね?とか勝手に思ったり。詳しいことは調べてませんが。

ま、利用シーンにもよりますがねえー

検証用のスクリプト


こんなのつかった。1000000個。

<?php
ini_set("memory_limit", -1);

$result = array();
foreach (range(1,1000000) as $i) {
    $result[mt_rand(1, 10)] = 0;
}

$r = array_keys($result);
<?php
ini_set("memory_limit", -1);

$result = array();
foreach (range(1,1000000) as $i) {
    $result[] = mt_rand(1, 10);
}

$r = array_unique($result);