質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

4589閲覧

PHPで10万件の配列x5つを高速処理させたい

meex

総合スコア66

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

1グッド

1クリップ

投稿2021/07/04 06:12

編集2021/07/04 06:14

環境

PHP 7系
Laravel Framework 8.49.0

やりたいこと

PHP

1$moto_data1 = [12345, 5, 12346, 9, 12347, 11, 12348, -1 , ...]; 2$moto_data2 = 同上; 3 ...

という配列があります。
合計5つあります。

偶数の要素は3600をかけることで時間に変換する必要があります。
奇数の要素は値を示しています。そのまま後続処理で活用します。

こういう並び方をした配列が5つあります。
※1つの配列につき、約10万件前後の要素数があります。

この時、現在、以下のソースで処理させようとしていますが、1つ分の配列を処理したところ、7秒かかってしまいました。

PHP

12次元配列を分割するメソッド 2 public function explodeTwoDimensional($tdArray): array 3 { 4 if (empty($tdArray)){ 5 var_dump($tdArray); 6 return [null,null]; 7 } 8 9 $date = $val = null; 10 $idx = 0; 11 $maxIdx = count($tdArray) - 1; 12 foreach ($tdArray as $arr){ 13 $date[] = $tdArray[$idx]; 14 $val[] = $tdArray[$idx + 1]; 15 16 $idx += 2; 17 if ($maxIdx <= $idx){ 18 break; 19 } 20 } 21 return [$date, $val]; 22 }

分割処理は、「microtime」で計測したところ、約0.0037秒で終わります。

PHP

1 $viewValue = []; ・・・結果表示用 2 $tmpVal = explodeTwoDimensional($moto_data1); 3$tmpVal[0] = 時間データ 4       $tmpVal[1] = 値データが入っています 5 6 foreach ($timeStamp as $time){ 7 $temp = null; 8 $idx = 0; 9 foreach ($tmpVal[0] as $valTime){ 10 if ($time=== $valTime){ 11 $temp = $tmpVal[1][$idx]; 12 $tmpVal= array_slice($tmpVal[0], $idx); 13              ↑過ぎた日付は無意味なので次の要素比較で比較しないよう配列を更新してます 14 break; 15 } 16 ++$idx; 17 } 18 $viewValue[] = $temp; 19 }

動きとしては、$timestampは、5つあるmoto_dataの日付がすべてマージされています。(マスターデータ)
10万件データ(moto_data1)は、マスターデータと比較して、日付があれば、その日付に対応する値をviewValueに入れる。なければnullを入れるという流れで組んでいます。

しかし、こうすると、マスターデータの件数xmoto_dataの数となるので、ループ数が跳ね上がり、処理時間が増加しているようです。

moto_data1だけでも7秒程度かかるので、5つあれば単純計算35秒ほどかかる見込みです。
しかし、許容される処理時間は、5つの配列をすべて処理したとしても、「3秒以内」に収めないといけません。

これを解決する方法はありますか?

BeatStar👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

質問文から、moto_dataで言うところの、keyがタイムスタンプ(5桁の数値)で、valueが1桁の数値の配列、という配列、例えば、

php

1$viewValue[12345] = [5,6,7,...] 2$viewValue[12346] = [9,10,11,...] 3$viewValue[12348] = [-1,-2,-3,...] 4 : 5 :

となる連想配列を作成したいと読み取りました。以下その前提で回答します。

とりあえず配列を分割する必要はありません。

  • 予めkeyが 配列$timestampの各値で、valueが空の配列である配列 $timestamp_hashを用意し、
  • $moto_dataから要素を2つずつ取り出し、
  • $moto_dataの時刻値が$timestamp_hashのkeyに存在すれば、$timestamp_hash[key]$moto_dataの値をプッシュする

とすることで、タイムスタンプの探索コストを大幅に減らすことができます。

実験用コード:

php

1<?php 2 3// テストダミーデータ10万件 4$moto_data = []; 5for($i = 0; $i < 100000; $i++){ 6 $moto_data[] = $i*513 % 100000; 7 $moto_data[] = $i % 20; 8} 9 10// timestampマスターデータ5万件とする。 11$timestamp = []; 12for($x = 0; $x < 50000; $x++){ 13 $timestamp[$x] = $x; 14} 15 16// $timestampの値をkeyとする配列を作成。valueは空の配列。 17// この空の配列に$moto_dataの値を入れていく。 18$timestamp_hash = []; 19foreach($timestamp as $time){ 20 $timestamp_hash[$time] = []; 21} 22echo count($timestamp)."\n"; 23echo count($timestamp_hash)."\n"; 24 25// テスト:ダミーデータの投入を5回繰り返す 26for($x = 0; $x < 5; $x++){ 27 $cnt = count($moto_data); 28 $i = 0; 29 while($i < $cnt){ 30 // $timestamp配列内に当該データの時刻がキーとなる要素があればanswerにpush 31 // 無ければ今回は何もしない 32 if(isset($timestamp_hash[$moto_data[$i]])){ 33 $timestamp_hash[$moto_data[$i]][] = $moto_data[$i+1]; 34 } 35 $i += 2; 36 } 37} 38// 確認用 39// foreach($timestamp_hash as $k => $v){ 40// echo "$k => ". count($v) . "\n"; 41// } 42 43?>

詳しい記載がなかったので、$timestampの中身は$moto_dataの半分である5万件と勝手に仮定しています。
作成したデータの書き出し時間を除けば私所有core i5-7500 のWindowsPCで100msちょっとくらいの実行速度です。
なお、$timestampのデータを$moto_dataと同数にすると150ms前後の実行速度となります。
マシンスペックがそれほど高くなくても3秒以内で十分収まるかと思います。

投稿2021/07/04 13:04

hope_mucci

総合スコア4447

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meex

2021/07/05 22:16

「先頭から探索」ではなく「要素の存在確認」によって有り無しを判定するという発想はなかったです!この思考を組み入れたところ、5つ行っても3s以内に収めることができました。アドバイスありがとうございます。
guest

0

直接の回答ではありませんが、
PHPを少しでも速く動かしたい - Qiita
にあるような細かな改善を試してみて、
少しでも速く動きそうな書き方を模索するのがよろしいかと。

あと、値渡しと参照渡しの違いはわかりますか?
参照による代入
メソッドに単に引き渡すと、10万件のデータを複製して渡しているはずなので、
細かくメソッドが持つ処理を分断してメソッドに引き渡して結果を受け取ってを繰り返すと、
複製する処理に時間とメモリを取られそう。
必要に応じて参照渡しで加工するといいかもしれません。

投稿2021/07/04 08:34

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問