This question already has answers here:
Performance of FOR vs FOREACH in PHP
(5 answers)
Closed 9 years ago.
Intro
If I loop in PHP, and know how many times I want to iterate, I usually use the for-loop like this:
for($y=0; $y<10; $y++) {
// ...
}
But lately I have seen someone use the foreach-loop:
foreach (range(1, 10) as $y) {
// ...
}
Now, I found the foreach-loop much more readable and thought about adopt this foreach-construct. But on the other side the for-loop is faster as you can see in the following.
Speed Test
I did then some speed tests with the following results.
Foreach:
$latimes = [];
for($x=0; $x<100; $x++) {
$start = microtime(true);
$lcc = 0;
foreach (range(1, 10) as $y) {
$lcc ++;
}
$latimes[$x] = microtime(true) - $start;
}
echo "Test 'foreach':\n";
echo (float) array_sum($latimes)/count($latimes);
Results after I runnt it five times:
Test 'foreach': 2.2873878479004E-5
Test 'foreach': 2.2327899932861E-5
Test 'foreach': 2.9709339141846E-5
Test 'foreach': 2.5603771209717E-5
Test 'foreach': 2.2120475769043E-5
For:
$latimes = [];
for($x=0; $x<100; $x++) {
$start = microtime(true);
$lcc = 0;
for($y=0; $y<10; $y++) {
$lcc++;
}
$latimes[$x] = microtime(true) - $start;
}
echo "Test 'for':\n";
echo (float) array_sum($latimes)/count($latimes);
Results after I runnt it five times:
Test 'for': 1.3396739959717E-5
Test 'for': 1.0268688201904E-5
Test 'for': 1.0945796966553E-5
Test 'for': 1.3313293457031E-5
Test 'for': 1.9807815551758E-5
Question
What I like to know is what would you prefer and why? Which one is more readable for you, and would you prefer readability over speed?
The following code samples are written in php under codeigniter framework’s benchmark library(it just to save my time as i am currently using these :D ), if you are using other languages, consider this as a pseudo code implement in your language way. There shouldn’t be any problem to implement this to any programming language. If you have experience with php/codeigniter, then you are lucky, just copy paste this code and test :) .
$data = array();
for($i=0;$i<500000;$i++){
$data[$i] = rand();
}
$this->benchmark->mark('code_start');
for($i=0;$i<500000;$i++){
;
}
$this->benchmark->mark('code_end');
echo $this->benchmark->elapsed_time('code_start', 'code_end');
echo "<br/>";
$this->benchmark->mark('code_start');
foreach($data as $row){
;
}
$this->benchmark->mark('code_end');
I have got 2 seconds difference between these two loops(one later one ran in around 3 seconds while first one ran in around 5 seconds). So, foreach loop won the ‘battle of for vs foreach’ here. However, you might be thinking, we won’t need such big loop; May be not in all cases, but there are some cases where long loops may be needed, like update big product database from web service/xml/csv etc. And, this example is only to aware you about the performance difference between them.
But, yes, they both have some exclusive use where they should exclusively because of extreme easiness/optimization. Like, if you are working in a loop where, on a certain condition the loop can be terminated. In this case, for loop will do the work with the most flexibility. On the other hand, if you are taking every objects/item from a list array and processing them, in this case, foreach will serve you best.
Related
I did a test and was really bummed to find that a standard foreach loop performed significantly faster than using array methods.
Using foreach:
$std_dev = 0;
$mean = self::calc_stat_mean($array);
$start = microtime(true);
foreach ($array as $value)
{
$std_dev += pow(($value - $mean), 2);
}
echo microtime(true) - $start;
Using array methods:
$mean = self::calc_stat_mean($array);
$start = microtime(true);
$std_dev = array_sum(array_map(function($value) use ($mean) {
return pow(($value - $mean), 2);
}, $array));
echo microtime(true) - $start;
Can someone tell me why this is? I feel the latter method just seems better written and cleaner than the former but the hit in speed isn't worth it.
The difference is so small that it isn't even worth worrying about.
Just pick something that matches your programming style, that you like better personally, and that will work better for your app.
Find other places to optimize... Don't stress over for, for each, and while!
I am in doubt what to use:
foreach(){
// .....
if(!in_array($view, $this->_views[$condition]))
array_push($this->_views[$condition], $view);
// ....
}
OR
foreach(){
// .....
array_push($this->_views[$condition], $view);
// ....
}
$this->_views[$condition] = array_unique($this->_views[$condition]);
UPDATE
The goal is to get array of unique values. This can be done by checking every time if value already exists with in_array or add all values each time and in the end use array_unique. So is there any major difference between this two ways?
I think the second approach would be more efficient. In fact, array_unique sorts the array then scans it.
Sorting is done in N log N steps, then scanning takes N steps.
The first approach takes N^2 steps (foreach element scans all N previous elements). On big arrays, there is a very big difference.
Honestly if you're using a small dataset it does not matter which one you use. If your dataset is in the 10000s you'll most definitely want to use a hash map for this sort of thing.
This is assuming the views are a string or something, which it looks like it is.
This is typically O(n) and possibly the fastest way to deal with tracking unique values.
foreach($views as $view)
{
if(!array_key_exists($view,$unique_views))
{
$unique_views[$condition][$view] = true;
}
}
TL;DR: foreach combined with if (!in_array()) is better.
Truthfully you should not really worry about what performs better; in most cases the difference is so small, its negligible (unless you're really doing some big data stuff). I would suggest to go with whatever seems more readable.
If you're interested, check out this script I wrote. It loops each case 100.000 times and both take between 50 and 200 ms.
https://3v4l.org/lkTCF
Note that array_unique() keeps the original keys so to counter that we also have to wrap the result with array_values().
In case the link ever dies:
<?php
$loops = 100000;
$start = microtime(true);
for ($l = 0; $l < $loops; $l++) {
$x = [1,2,3,4,6,7,8,9];
for ($i = 0; $i <= 10; $i++) {
if (!in_array($i, $x)) {
$x[] = $i;
}
}
}
$duration = microtime(true) - $start;
echo "in_array took $duration<br>".PHP_EOL;
$start = microtime(true);
for ($l = 0; $l < $loops; $l++) {
$x = [1,2,3,4,6,7,8,9];
$x = array_values(array_unique(array_merge($x, [0,1,2,3,4,5,6,7,8,9,10])));
}
$duration = microtime(true) - $start;
echo "array_unique took $duration<br>".PHP_EOL;
I know the more efficient way to have a loop over array is a foreach, or to store count in a variable to avoid to call it multiple times.
But I am curious if PHP have some kind of "caching" stuff like:
for ($i=0; $i<count($myarray); $i++) { /* ... */ }
Does it have something similar and I am missing it, or it does not have anything and you should code:
$count=count($myarray);
for ($i=0; $i<$count; $i++) { /* ... */ }
PHP does exactly what you tell it to. The length of the array may change inside the loop, so it may be on purpose that you're calling count on each iteration. PHP doesn't try to infer what you mean here, and neither should it. Therefore the standard way to do this is:
for ($i = 0, $length = count($myarray); $i < $length; $i++)
PHP will execute the count each time the loop iterates. However, PHP does keep internal track of the array's size, so count is a relatively cheap operation. It's not as if PHP is literally counting each element in the array. But it's still not free.
Using a very simple 10 million item array doing a simple variable increment, I get 2.5 seconds for the in-loop count version, and 0.9 seconds for the count-before-loop. A fairly large difference, but not 'massive'.
edit: the code:
$x = range(1, 10000000);
$z = 0;
$start = microtime(true);
for ($i = 0; $i < count($x); $i++) {
$z++;
}
$end = microtime(true); // $end - $start = 2.5047581195831
Switching to do
$count = count($x);
for ($i = 0; $i < $count; $i++) {
and otherwise everything else the same, the time is 0.96466398239136
PHP is an imperative language, and that means it is not supposed to optimize away anything that can possibly have any effect. Given that it's also an interpreted language, it couldn't be done safely even if someone really wanted.
Plus, if you simply want to iterate over the array, you really want to use foreach. In that case, not only the count, but the whole array will be copied (and you can modify the original one as you wish). Or you can modify it in place using foreach ($arr as &$el) { $el = ... }; unset($el);. What I mean to say is that PHP (as any other language) often provides better solutions to your original problem (if you have any).
I'm attempting to solve Project Euler in PHP and running into a problem with my for loop conditions inside the while loop. Could someone point me towards the right direction? Am I on the right track here?
The problem, btw, is to find the sums of all prime numbers below 2,000,000
Other note: The problem I'm encountering is that it seems to be a memory hog and besides implementing the sieve, I'm not sure how else to approach this. So, I'm wondering if I did something wrong in the implementation.
<?php
// The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
// Additional information:
// Sum below 100: 1060
// 1000: 76127
// (for testing)
// Find the sum of all the primes below 2,000,000.
// First, let's set n = 2 mill or the number we wish to find
// the primes under.
$n = 2000000;
// Then, let's set p = 2, the first prime number.
$p = 2;
// Now, let's create a list of all numbers from p to n.
$list = range($p, $n);
// Now the loop for Sieve of Eratosthenes.
// Also, let $i = 0 for a counter.
$i = 0;
while($p*$p < $n)
{
// Strike off all multiples of p less than or equal to n
for($k=0; $k < $n; $k++)
{
if($list[$k] % $p == 0)
{
unset($list[$k]);
}
}
// Re-initialize array
sort ($list);
// Find first number on list after p. Let that equal p.
$i = $i + 1;
$p = $list[$i];
}
echo array_sum($list);
?>
You can make a major optimization to your middle loop.
for($k=0; $k < $n; $k++)
{
if($list[$k] % $p == 0)
{
unset($list[$k]);
}
}
By beginning with 2*p and incrementing by $p instead of by 1. This eliminates the need for divisibility check as well as reducing the total iterations.
for($k=2*$p; $k < $n; $k += $p)
{
if (isset($list[k])) unset($list[$k]); //thanks matchu!
}
The suggestion above to check only odds to begin with (other than 2) is a good idea as well, although since the inner loop never gets off the ground for those cases I don't think its that critical. I also can't help but thinking the unsets are inefficient, tho I'm not 100% sure about that.
Here's my solution, using a 'boolean' array for the primes rather than actually removing the elements. I like using map,filters,reduce and stuff, but i figured id stick close to what you've done and this might be more efficient (although longer) anyway.
$top = 20000000;
$plist = array_fill(2,$top,1);
for ($a = 2 ; $a <= sqrt($top)+1; $a++)
{
if ($plist[$a] == 1)
for ($b = ($a+$a) ; $b <= $top; $b+=$a)
{
$plist[$b] = 0;
}
}
$sum = 0;
foreach ($plist as $k=>$v)
{
$sum += $k*$v;
}
echo $sum;
When I did this for project euler i used python, as I did for most. but someone who used PHP along the same lines as the one I did claimed it ran it 7 seconds (page 2's SekaiAi, for those who can look). I don't really care for his form (putting the body of a for loop into its increment clause!), or the use of globals and the function he has, but the main points are all there. My convenient means of testing PHP runs thru a server on a VMWareFusion local machine so its well slower, can't really comment from experience.
I've got the code to the point where it runs, and passes on small examples (17, for instance). However, it's been 8 or so minutes, and it's still running on my machine. I suspect that this algorithm, though simple, may not be the most effective, since it has to run through a lot of numbers a lot of times. (2 million tests on your first run, 1 million on your next, and they start removing less and less at a time as you go.) It also uses a lot of memory since you're, ya know, storing a list of millions of integers.
Regardless, here's my final copy of your code, with a list of the changes I made and why. I'm not sure that it works for 2,000,000 yet, but we'll see.
EDIT: It hit the right answer! Yay!
Set memory_limit to -1 to allow PHP to take as much memory as it wants for this very special case (very, very bad idea in production scripts!)
In PHP, use % instead of mod
The inner and outer loops can't use the same variable; PHP considers them to have the same scope. Use, maybe, $j for the inner loop.
To avoid having the prime strike itself off in the inner loop, start $j at $i + 1
On the unset, you used $arr instead of $list ;)
You missed a $ on the unset, so PHP interprets $list[j] as $list['j']. Just a typo.
I think that's all I did. I ran it with some progress output, and the highest prime it's reached by now is 599, so I'll let you know how it goes :)
My strategy in Ruby on this problem was just to check if every number under n was prime, looping through 2 and floor(sqrt(n)). It's also probably not an optimal solution, and takes a while to execute, but only about a minute or two. That could be the algorithm, or that could just be Ruby being better at this sort of job than PHP :/
Final code:
<?php
ini_set('memory_limit', -1);
// The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
// Additional information:
// Sum below 100: 1060
// 1000: 76127
// (for testing)
// Find the sum of all the primes below 2,000,000.
// First, let's set n = 2 mill or the number we wish to find
// the primes under.
$n = 2000000;
// Then, let's set p = 2, the first prime number.
$p = 2;
// Now, let's create a list of all numbers from p to n.
$list = range($p, $n);
// Now the loop for Sieve of Eratosthenes.
// Also, let $i = 0 for a counter.
$i = 0;
while($p*$p < $n)
{
// Strike off all multiples of p less than or equal to n
for($j=$i+1; $j < $n; $j++)
{
if($list[$j] % $p == 0)
{
unset($list[$j]);
}
}
// Re-initialize array
sort ($list);
// Find first number on list after p. Let that equal p.
$i = $i + 1;
$p = $list[$i];
echo "$i: $p\n";
}
echo array_sum($list);
?>
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
In this situation, is it better to use a loop or not?
echo "0";
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";
echo "6";
echo "7";
echo "8";
echo "9";
echo "10";
echo "11";
echo "12";
echo "13";
or
$number = 0;
while ($number != 13)
{
echo $number;
$number = $number + 1;
}
The former may be a little faster. The latter is a lot more readable. Choice is yours ;)
Even better would be
$totalWhatevers = 14;
for ($number = 0; $number < $totalWhatevers ; $number++)
{
echo $number;
}
Where 'totalWhatevers' is something descriptive to tell us what you are actually counting.
It's clearer to use a loop; as a rule of thumb, if you use fewer lines of code to loop, do so.
Your loop could be written more succinctly:
foreach (range(0,13) as $n)
echo $n, "\n";
I'd use a for loop, just to keep everything out in the open (your original loop seems to only print up to 12):
for ($number = 0; $number <= 13; $number++)
{
echo $number;
}
It's a lot cleaner then writing out a million 'echo', and the code is fairly self explanatory.
$string = "<?php \n";
$repeatNum = 20;
for($i = 0; $i < $repeatNum; $i++)
{
$string .= "echo \"" . $number . "\"; \n";
}
$string = "?>";
Now you can either
eval($string);
or
file_put_contents("newfile.text", $string);
and you will get a file with all the echos!
Note: This is not really a 'serious' answer. If you really want to create a PHP file with a number of echos, it works, but evaling the statement at the end is probably not the best idea for regular programming practice.
Depending on what you are trying to do, a loop could help to keep your code clearer and simpler to update.
For example, when the number of display could vary, you could use a config variables.
$repeat = 20;
for ($i = 0; $ < $repeat; ++$i) {
echo $i;
}
The mistake is in thinking that a loop generates code. This is not the case at all.
echo "0";
echo "1";
echo "2";
echo "3";
PHP will come along and execute each of these statements one by one.
for ($i = 0; $i <= 3; ++$i) {
echo $i;
}
In this case, PHP executes the same echo statement four times. Each time the end of the block is reached (a block being code between curly braces) execution jumps back to the condition. If the condition is still true, the block executes again.
Which method offers the best performance? It is very, very hard to tell.
Slowdown of method 1) The greater the range of numbers to echo, the more echo statements that have to be parsed in the script.
Slowdown of method 2) The greater the range of numbers to echo, the more times execution has to jump, the more times a condition has to be tested, and the more times a counter has to be incremented.
I do not know which scenario leads to more CPU instructions, or which leads to more memory usage. But as someone who has programmed before, I know a secret: it doesn't matter. The difference in execution will probably weigh around a few ten millionths of a second!
Therefore, the only way to make the effects become noticeable at all is if you are echoing ten million numbers, in which case one method might take a second more than the other. Isn't this a worthy gain though? No! By the time we are echoing ten million numbers, we are going to be spending minutes on either method. Only the difference between them will differ by a second, which is completely negligible. Not to mention, who knows which one is better anyhow?
As a programmer, the best thing you can do is make your code readable and maintainable. A loop is much easier to understand than a page of echo lines. With a loop I know you haven't missed any intermediate numbers, but with echoes I have to check every single line.
Technical jargon version: both algorithms have complexity O(n). There can only be a constant difference in their performance, and if that constant is not particularly large, it is negligible.
What do you mean by better? Better for the parser? better for the computer? Faster execution time? I can tell you that Making a loop is always better, For the people working with your code and for the system.