[PHP] 多重配列の処理をもっと早く処理できるようにする方法
2重ループは、メモリキャッシュすることで、高速化できるので、仕事でやってみたらかなり効果的だったという備忘録です。
多重ループはどんな時に発生する?
2つの別々のデータベースから、片方からはマスターデータ(ユーザーデータなど)、もう片方からは実行データ(売り上げデータなど)をリストで取得して、それらを突合する時に多重ループで処理する必要に迫られます。サンプル
営業部門のユーザー登録されているデータベースAから、ユーザーリストの取得 ユーザーデータJSON[
{
"id" : 1,
"name" : "tanaka"
},
{
"id" : 2,
"name" : "suzuki"
},
{
"id" : 3,
"name" : "naito"
}
]
次にデータベースBから、売上実績データを取得
売り上げデータJSON
[
{
"id" : 1,
"price" : 10000,
"user_id" : 1
},
{
"id" : 2,
"price" : 5000,
"user_id" : 3
},
{
"id" : 3,
"price" : 7500,
"user_id" : 2
}
]
PPAP合体!
上記で取得したデータリスト2つをuser_idを元に結合してみたいと思います。<?php
$a = [
[
"id" => 1,
"name" => "tanaka"
],
[
"id" => 2,
"name" => "suzuki"
],
[
"id" => 3,
"name" => "naito"
]
];
$b = [
[
"id" => 1,
"price" => 10000,
"user_id" => 1
],
[
"id" => 2,
"price" => 5000,
"user_id" => 3
],
[
"id" => 3,
"price" => 7500,
"user_id" => 2
]
];
foreach($a as $a_key => $a_val){
foreach($b as $b_key => $b_val){
if($a_val['id'] === $b_val['user_id']){
$b[$b_key]['name'] = $a_val['name'];
break;
}
}
}
echo '<pre>';
print_r($b);
実行結果
Array
(
[0] => Array
(
[id] => 1
[price] => 10000
[user_id] => 1
[name] => tanaka
)
[1] => Array
(
[id] => 2
[price] => 5000
[user_id] => 3
[name] => naito
)
[2] => Array
(
[id] => 3
[price] => 7500
[user_id] => 2
[name] => suzuki
)
)
数が少なくて対した時間がかかりませんが、これが、ユーザーリストも売り上げリストも1000ずつぐらいの桁数があると考えると、100万回のループ処理が発生します。
途中でbreak処理をしていますが、こうした場合は、最大値で考えたほうがいいでしょう。
メモリ化して高速化
次に、上記のように無駄にループ処理を行わずに、次のようにメモリにデータを保持してみるともっとスッキリ処理できます。 データは同じなので、合体処理の箇所のみ書き換えてみました。$a2 = [];
foreach($a as $a_key => $a_val){
$a2[$a_val['id']] = $a_val;
}
foreach($b as $b_key => $b_val){
$b[$b_key]['name'] = $a2[$b_val['user_id']]['name'];
}
echo '<pre>';
print_r($b);
これで同じ結果が返ります。
なんだかプログラミングもスッキリするし、処理速度も早くなるならこっちのほうがいいですね。
ただし、上記のプログラムは、いくつか気をつける点があり、user_idが必ず存在する場合に限ります。
if文を入れ込めばいいだけですが・・・