DBやCSVファイルからデータを取得する際、配列として取得することはよくある。
例えば、DB上の大量のデータを配列として取得して、手元にある別のデータとの重複の照合を行うこともあるだろう。
ここでは、配列同士の比較をできる限り高速に行うことを主眼に置く。
実行速度は処理に要する時間を計測することで、遅い or 速いを判断する。
【PHP】処理の速度を計測する方法
【PHP公式】microtime — 現在の Unix タイムスタンプをマイクロ秒まで返す
##配列の準備
はじめに、10万個の要素を持つ配列を2つ準備する。
$data
には0〜99,999の100,000個の数字
$randomData
には0〜500,000のうちランダムに100,000個の数字
が格納されている。
for ($i = 0; $i < 100000; $i++) {
$data[] = $i;
}
for ($i = 0; $i < 100000; $i++) {
$randomData[] = rand(0, 500000);
}
#1. 重複する要素を取得する
##1.1 foreach
で普通に比較する
$data
のうち$randomData
に含まれるものを数え上げる際にまず思い浮かぶのは、次の方法だろう。それぞれの要素数が少なければ、すぐに終わるが10万件同士の比較になるとそうはいかない。また、実際の業務ではもっと複雑な処理をしなければならないことも多く、あまり使い勝手は良くない。
何よりもコードが見づらい。
foreach ($data as $i) {
foreach ($randomData as $j) {
if ($i == $j) {
$result1[] = $i;
break;
}
}
}
121.19333004951 seconds.
Count: 18016 //重複している要素の数
##1.2 array_intersect
を用いる
(PHP4.0.1以上)
【PHP公式】array_intersect — 配列の共通項を計算する
array_intersect
は、第一引数のうち第二引数以降に含まれるものが返り値になる。このとき、値の型とキーは保持される。また、値の比較はstring(文字列)にキャストした上で行われ、完全一致したものだけが返される。
実際に今回のコードに適用してみると、驚くほど簡潔で清々しいほどである。
そして実行時間は、1.1と比較して約500分の1である。
$result2 = array_intersect($data, $randomData);
0.24257612228394 seconds.
Count: 18016 //同じプログラム内で行ったので同じ重複数
#2. 重複しない要素を取得する
##2.1 foreach
で普通に比較する
foreach
を使って、ある程度実行速度を速くするためには次のコードが思い浮かんだ。コードの見づらさは、ご容赦を。
**「foreachでも、もっといい方法あるよ」**って方は是非教えていただきたい。
このコードでは、$data
のうち$randomData
に含まれないものを取得している。
実行時間は1.1とほぼ同じ結果となった。
foreach ($data as $i) {
foreach ($randomData as $j) {
if ($i == $j) {
break;
}
}
if ($i != $j) {
$result1[] = $i;
}
}
121.41330385208 seconds
Count: 82026 //重複していない要素の数
##2.2 array_diff
を用いる
(PHP4.0.1以上)
【PHP公式】array_diff — 配列の差を計算する
array_diff
は第一引数のうち第二引数以降に含まれないものが返り値になる。このとき、値の型とキーは保持され、値の比較もarray_intersect
同様に行われる。
それでは、コードと実行結果を見てみよう。
実行時間は、なんと2.1の約4300分の1である。
$result2 = array_diff($data, $randomData);
0.02807092666626 seconds
Count: 82026
##まとめ
array_intersect
とarray_diff
は、配列を高速比較できる素晴らしい関数である。
実際の業務では、もっとデータ量の大きいものを比較することは大いにあり得る。そのようなときは、PHPで準備されている配列用の関数を考慮しながら、実装方針を固めるようにしていきたい。
【PHP公式】配列 関数