ぐらめぬ・ぜぷつぇんのはてダ(2007 to 2011)

2007年~2011年ごろまで はてなダイアリー に書いてた記事を引っ越してきました。

array_flipベンチマーク追記

id:uunfoさんが先日の日記を受けてさらなる検証をしてくれました。ありがとうございます。

しかしこのように同じ配列に対して何度も検索をかけるといった状況はそうあるものでしょうか?
実際のソース中のin_arrayをarray_flipを使ったものに置き換えることを考えるとこのソースは不自然です。

in_arrayとarray_flip+array_key_existsの比較3 - ”improve it!”

ご指摘の通り。確かに、実際に高速化を図ろうとin_array()を書き換えるシーンを想定すると明らかに先日のベンチマークのソースは不自然でした。というか、数字の意味的におかしいですね。in_array()の書き換えが array_flip() + isset()/array_key_exists()になるのですから、array_flip()とisset()/array_key_exists()を分離しては数字の意味が違ってしまいます。

重ね重ねご指摘と検証、ありがとうございました。

数字を改めて眺めると確かにarray_flip()のコストが大きいことは確かです。id:uunfoさんが書いているとおり、array_flip()のコストをin_array()が上回るようなシーンであれば、限定的にarray_flip()の効果が発揮できる、という条件付きになるようです。

Benchmarkって怖い。数字の意味をよくよく考えないと、今回みたいにミスる。

というか自分のソースを見てて今気づいたんですが、

$sz = 10000;
$arr1 = array();
for ($i = 0; $i < $sz; $i++) {
    $arr1[] = mt_rand(1, $sz);
}

これ、自分、何がしたかったんでしょうね。多分ランダムな値を10,000件配列に詰めたかったと思うんですが、これ、値が重複しますよね。
・・・そうなると、array_flip()した結果の配列の要素数が変わっちゃいますよね。

・・・
・・・

普通にバグってるし。_| ̄|○
Benchmarkの役、してねぇ。

気分を変えて。

余談: はじめからハッシュを使えばいいのでは?
array_flipのコストが高いことがわかりました。それならはじめからそんなのを使わないようにすればいいんです。つまりはじめからハッシュのキーに値を保存しておけばいいのです。

in_arrayとarray_flip+array_key_existsの比較3 - ”improve it!”

本当に高速化を目指すのであればそうなるかと思います。ただ・・・すみません。実際問題、in_array()だけでもミリ秒オーダーで動いていますので、in_array()だけでもお腹一杯になりそうな予感です。
また、注意が必要なのはこれらはキー、値両方とも重複が無いデータ群を暗黙裏に(バグってたけど、書いた当時の当人は(w )想定していて(だからこそ何も考えずにarray_flip()噛ましているわけで)、その上である値が配列に存在するか否かを引き当てるのにどうすれば速いかを見ています。
ソートをしたい場合や、値に重複があるような状況下では成立しなくなりますので、これもまた条件付きで、となるので(自分自身)注意が必要だと思います。

※ちょい追記
先日のはPHP4.4.7で動かしてたのですが、ふと、PHP5.2.4で動かしてみたところ、array_flip()のAverageがPHP4の6割程度まで減っていました。

PHP4.4.7:
> php array_flip_benchmark03_2.php
...
-----------
Average :
        array_flip() : 0.0119961 << 11 - 12ms程度
        hit : 5.47E-005 (1ms以下)
        total : 0.0120508

で、

PHP5.2.4:
> php array_flip_benchmark03_2.php
....
-----------
Average :
        array_flip() : 0.0063355 << 6 - 5ms程度
        hit : 0.0001182 (1ms以下)
        total : 0.0064537

という具合です。内部で高速化されたんでしょうか。
array_flip_benchmark01_2.phpについてはPHP4/5とも、Averageは1ms程度で変わりませんでした。