I execute the code

<?php $arr = file('arr.txt'); $sum = 0; foreach ($arr as $key => $value) { $sum = array_sum(array_slice($arr,$key,30)); if($sum > 50) { echo $key . ' ' . $sum . "<br>"; } } ?> 

That is, I explain:

 Π‘ΡƒΠΌΠΌΠΈΡ€ΡƒΡŽ ΠΏΠΎ порядку Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Ρ‹: Π‘ΡƒΠΌΠΌΠ° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ с 0 ΠΏΠΎ 30 Π‘ΡƒΠΌΠΌΠ° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ с 1 ΠΏΠΎ 31 Π‘ΡƒΠΌΠΌΠ° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ с 2 ΠΏΠΎ 32 Π‘ΡƒΠΌΠΌΠ° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ с 3 ΠΏΠΎ 33 Π‘ΡƒΠΌΠΌΠ° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ с 4 ΠΏΠΎ 34 .. И Ρ‚Π°ΠΊ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π°. 

I get the error:

 Fatal error: Maximum execution time of 180 seconds exceeded in E:\OSPanel\domains\arr\index.php on line 6 

The file arr.txt is 200k integers (0-100 approximately)

can you optimize, speed up the function? It is desirable without complications of the code - so everything falls out of my head. if not - how to give time to perform?

  • and what happens here in general, write in Russian. - teran pm
  • Never search for the text of the error in Google, otherwise you will find the answer and you will not be able to write another question on SO. - u_mulder 1:38 pm
  • @u_mulder how to optimize the code also not to search? - Adm Tea
  • @u_mulder answer to the question about this error will be disabling time-limit for example, although you can improve the algorithm here, because the slices constantly allocate memory, and the summation of the array nafig is not necessary, except the first. then only + end do it. That is, here, in addition to the problem with the limit, the algorithm is also not optimal. although it is clear - teran
  • here the banal function rangeSum($arr, $start, $len = 30){ $sum = 0; while($len--) $sum+=$arr[$start++]; return $sum; } function rangeSum($arr, $start, $len = 30){ $sum = 0; while($len--) $sum+=$arr[$start++]; return $sum; } function rangeSum($arr, $start, $len = 30){ $sum = 0; while($len--) $sum+=$arr[$start++]; return $sum; } can give a slight performance boost due to the elimination of 200k slices of the array (the end test must be true) - teran

2 answers 2

In general, if there is a sufficiently large file, no matter how optimal the algorithm, you will still run into the time limit. For obviously large tasks, it is disabled.

Let's see what and how it affects performance. I generated an array of 200k values ​​and wrote it into a file. At the time of the end of generation, the amount of used memory ( memory_get_usage() ) was 29 MB.
Then I turned off the time limit ( set_time_limit(0) ) and started your script to check how long it will be executed, and the tone was completed after 770 seconds.

We assume that the main reason for the long processing is that the slice is executed 200k times (the long slice is not in itself, but it is likely that the memory manager constantly allocates something and the collector destroys it). If you replace array_sum(array_slice( ... )) with a function that counts the sum of elements manually

 $rangeSum = function($data, $s) use ($count){ $sum = 0; $end = min($s+30, $count); while($s < $end){ $sum += $data[$s++]; } return $sum; }; 

running time - 1.4 seconds.

The next option is to calculate the sum of the first 30 items. And move on along the array. Subtract the first, add the following:

 $i = 0; while($i < 30) $sum += $arr[$i++]; $x = $sum > 50 ? 1 : 0; for($i = 30; $i < $count; $i++){<--> $sum += -$arr[$i-30] + $arr[$i]; if($sum > 50) $x++; } 

Here I neglected the end of the array a little, and in fact I don’t count the last 30 sums, but the result is 0.25 sec.

There is another option - to read the file line by line. But since You will need to store the current 30 elements in the array and do shift / push each time (to store this -30 element), then its performance will be below ~ 0.35 seconds, but you always store only 30 values, not 200 thousand, so the memory consumption will be minimal .

 while( ($v = fgets($f)) !== false){ $m = array_shift($values); $sum += -$m + $v; $values[] = $v; if($sum > 50) $x++; } 

previously we have already counted the first 30 lines and summed it up.

PS: all of the above code is taken out of context and not complete, just to convey meaning

  • also note that if you have numbers from 0 to 100, and you count the sum of 30 such values, then it will almost always be more than 50. in my case, with rand, numbers from 0 to 30 were generated, and in 199998 the amount was greater. So if you display the keys and the amount, then get ready for a short delay to get 30 megabytes of text in response - teran
  • The numbers are mostly not large in the array - Adm Tea
  • Took the second option (+ next, - previous element) - Adm Tea

Well, if nothing is confused, then you can -

 <?php $arr = file('arr.txt'); $sum = array_sum(array_slice($arr,0,30)); for($i = 1; $i<count($arr); $i++) { if($sum > 50) { echo ($i-1) . ' ' . $sum . "<br>"; } $sum = $sum + $arr[$i] - $arr[$i-1] ; } ?>