PDA

View Full Version : array_keys & FOR versus FOREACH



weegillis
06-05-2010, 05:39 PM
I'm looking for a way to convert this procedure from a FOREACH loop to a FOR loop with array_keys as the control.

The initial array ($pages) consists of KEY and VAL, where VAL is a one dimension array consisting of six elements; i.e., $pages['key'] = array( "","",0,"","","");

In this procedure, only the key and root val element are required (both are strings). The foreach loop builds a stack of all html statements, one LI/LI per key. The active page is detected and href routed to content on that page. The second while loops split the stack in two strings.

$page is either a match to a key, or is null.
$pNm is either a corresponding page name if $page is set, or is null.

The above two variables were derived from the initial array earlier in the script.

$href is only applied to the active page if $page is set.
$lns and $rns are the only variables needed past this point.



$href = (!$page) ? NULL : "<a href=\"#content\" title=\"Now reading " . $pNm . "\" class=\"active\">";
$c = 1;
$stack = array();
foreach($pages as $key => $val) {
$s = "<li id=\"r" . $c . "\">";
$s .= ($page!=$key) ? "<a href=\"/index.php?pg=" . $key . "\" title=\"" . $val[0] . "\">" : $href;
$s .= "<span>" . $val[0] . "</span></a></li>\n";
$stack[] = $s;
$c++;
}
$lns = "";
$rns = "";
$c = 0;
$l = 3;
$r = 2;
while($c < $l) {
$lns .= $stack[$c];
$c++;
}
while($c < ($l + $r)) {
$rns .= $stack[$c];
$c++;
}

DaveSawers
06-06-2010, 09:28 AM
If the foreach works, why bother changing it?

weegillis
06-06-2010, 01:57 PM
Short answer? Speed. There are faster ways to do this.

FOREACH, I'm told, is a real hog on resources, both CPU and memory. It's such a simple task, why use a complex process if a simple one will work.

You're right, though, Dave. It works, why change it? In a sense, the procedure is so short-lived (only a half dozen iterations) that any speed improvement would not result in a great time improvement. I would like to think this one through, even if it's just for the sake of tackling it.

Some days even the easy stuff is tough to wrap one's head around. As a newbie coder it's always easier to fall through a trap hole than see it. I only recently became aware of the different server load variations between one type of loop and another. This exercise will at least add one more rule of thumb to my logic.

kgun
06-07-2010, 09:14 AM
If the foreach works, why bother changing it?
Agree.


You will hardly notice a difference for arrays with less than 10 000 elements.
If it is an expermiment, there are other (inbuild) php data structure that may increase the speed of your application. You can of course solve the same problem in two (alternatively a twodimensional) array(s). I doubt it is faster. If you find a faster loop, then tell us.
And like echo is faster than print, while loops are marginally faster than for loops.
What about the redability of code?
Study the subject of object overloading (http://www.webproworld.com/webmaster-forum/threads/93349-Professional-PHP-6?p=481593&viewfull=1#post481593), and you will at least work more efficiently and reduce code drastically.
Don't forget PHP and unicode. (http://www.web3logistics.com/#unicode-and-multilingual-sites)
If speed is the main concern, I would not us an interpreted language at all.

weegillis
06-07-2010, 03:48 PM
Excellent points and resources, kgun. Thanks. I'm definitely with you on point 4, readability. I like to think that pretty code is not just for looks, but for the next person to come along that has to reason it out.

I may have moved one step closer to simplifying things by going to an indexed array from a keyed one. This should accommodate simpler loops, but I haven't got there yet:
$pages = array(
array("keya","","",0,"","",""),
array("keyb","","",0,"","",""),
array("keyz","","",0,"","","")
}
Now, rather than 'foreach($pages as $key => $val) {}', the statement is reduced to 'foreach($pages as $val) {}'.

Furthermore, I've created a small library consisting of three classes:

bobbin() for handling the query and setting $page, as well as pre-loading behavior data if $page is set;
spool() for creating the HTML stack (custom navigation); and,
thread() for distributing the stack over one (left only or right only) or both UL's in the generated page.

bobbin() and spool() are passed the initial array, and thread() is passed a value for left column height. global variables tie everything together.



function bobbin($x) {
global $page, $pNm, $eId, $eIx, $aWo, $bWo, $cWo;
if($page) {
$f = FALSE;
foreach($x as $y) {
$f = ($page === $y[0]);
if($f) {
$pNm = $y[1];
$eId = ($y[2]) ? $y[2] : NULL;
$eIx = ($y[3]) ? $y[3] : NULL;
$aWo = ($y[4]) ? $y[4] : NULL;
$bWo = ($y[5]) ? $y[5] : NULL;
$cWo = ($y[6]) ? $y[6] : NULL;
break;
}
}
}
$page = ($f) ? $page : NULL;
}
function spool($x) {
global $page, $stack, $hrf;
$c = 1;
foreach($x as $y) {
$s = "<li id=\"r" . $c . "\">";
$s .= ($page == $y[0]) ? $hrf : "<a href=\"/index.php?pg=" . $y[0] . "\" title=\"" . $y[1] . "\">";
$s .= "<span>" . $y[1] . "</span></a></li>\n";
$stack[] = $s;
$c++;
}
}
function thread($x) {
global $stack, $lns, $rns;
$s = sizeof($stack);
$c = 0;
while($c < $x && $c < $s) {
$lns .= $stack[$c];
$c++;
}
while($c < $s) {
$rns .= $stack[$c];
$c++;
}
}


The above logic has been removed to a separate .inc file for re-usability, and clarity in the main source, which is quite busy, as it is. Overall page performance is snappy, and does 'appear' to be a bit quicker than the earlier version.

a53mp
06-07-2010, 04:50 PM
Did you actually run load time tests to see if the two versions made any difference?

weegillis
06-08-2010, 05:35 AM
Definitely, no. Perceived page load times. I wouldn't know the first thing about actual load testing.

Might it be possible to use Inspect Element in Chrome or Safari and see? Like kgun said, if the array size is under 10 000 elements, the speed difference is negligible. I'm content with that, though perhaps not content enough to settle for code that can be made more efficient, or better tuned to its purpose..

The biggest concern I have right now is my total ignorance of the load placed on my host server. What remains in my capacity is to learn how to minimize my own effects; ergo this exercise.

MrGamm
06-13-2010, 11:53 PM
I see what you are asking... foreach is so convenient in so many cases that I almost exclusively use it.

I think you start to run into performance hits when you go a little overboard with explode() and split(). The multibyte functions are worth paying attention to...

You could try this...




$arr = array();

for($x=0;$x<10000;$x++){
$arr[$x] = array('left','right');
}

// TEST THE WHILE LOOP AND PRINT THE EXECUTION TIME...

$start = microtime(true);
$c = count($arr);
while($c){
$arr[$c][2]=$arr[$c][0].' - '.$arr[$c][1];
$c--;
}
print(($start-microtime(true)).'<br>');

// TEST THE FOREACH LOOP AND PRINT THE EXECUTION TIME...

$start = microtime(true);
foreach($arr as $a => $b){
$arr[$a][2]=$b[0].' - '.$b[1];
}
print(($start-microtime(true)).'<br>');

// TEST THE FOR LOOP AND PRINT THE EXECUTION TIME...

$start = microtime(true);
$c = count($arr);
for($x=0;$x<$c;$x++){
$arr[$x][2]=$arr[$x][0].' - '.$arr[$x][1];
}
print(($start-microtime(true)).'<br>');



EDIT Added MicroTime... I notice the foreach being about twice as slow as the while and the for loops.

I learned at one point you could even go so far as to change the while to a do{}while(); to save a cycle somewhere...





$start = microtime(true);
do{
$arr[$x][2]=$arr[$x][0].' - '.$arr[$x][1];
}while($c--);
print(($start-microtime(true)).'<br>');

// THIS MIGHT RECALCULATE THE LENGTH OF THE ARRAY ON EACH CYCLE...

$start = microtime(true);
for($x=0;$x<count($arr);$x++){
$arr[$x][2]=$arr[$x][0].' - '.$arr[$x][1];
}
print(($start-microtime(true)).'<br>');



IN the end... what makes sense and makes it easier to manage works best...

weegillis
06-14-2010, 05:43 PM
Thanks, MrGamm for the timing procedures. FOR seems to have it, hands down. FOREACH is definitely the slowest (must use the most CPU clicks?). Is the fact foreach must first make a copy of the array before execution a factor in the time it takes, or is just more intensive?

I did run an online load speed test on the site and am satisfied with the load time of 2.5 s on 56K connection. This project is not a good one for actual testing because of the minimal size of the array. One would expect any of the versions to be about the same for this small of a data space.

williamc
06-14-2010, 06:33 PM
$count = count($array);
for($i=0; $i<$count+1; $i++){
.... now do something with $array[$i]

kgun
06-15-2010, 06:07 AM
$count = count($array);
for($i=0; $i<$count+1; $i++){
.... now do something with $array[$i]
Marginally faster:
$count = count($array);
$i=0;
while ($i != $count) {
... do something with $array[$i]
++$i;
}
What about making a compiled c version on the server where the results can be read by PHP, phyton, ...

kgun
06-15-2010, 10:20 AM
What about making a compiled c version on the server where the results can be read by PHP, phyton, ...
Here is a simple old C++ example.


/*

Borland C++ - (C) Copyright 1994 by Kjell G. Bleivik

COUNT.CPP: Test the efficieny of the processor.

*/
#include <iostream.h>
#include <time.h>
//#include <stdlib.h>
int main()
{
clock_t start, end;
start = clock()/CLOCKS_PER_SEC;
unsigned long i=0;
while (i <= 100000000){++i;} //Counts to 100 Mill.

end = clock()/CLOCKS_PER_SEC;
cout << "\n Counted to 100 million in" << end - start << " seconds\n"
<< endl;

return 0;
}
When we tested that in the Central Bank of Norway in the mid 1990's, the Simula compiler was faster;) But the count on both compilers were done in less than 30 seconds if I remember correctly. I could have tested it vs an interpreted PHP program, but have more important things to do.

MrGamm
06-15-2010, 06:44 PM
@weegillis (http://www.webproworld.com/webmaster-../members/8156-weegillis)

I honestly don't know if it takes more "clicks"... I can run the tests, and get inaccurate readings from one to the next. I think it probably has something to do with load balancing or threading which could make the tests inaccurate from one run to the next.

ForEach... it could make a copy, I'm not much a C programmer... but PHP is basically a scripting extension of C. You can download the source code for PHP which is written in C and find out I guess.

http://www.php.net/downloads.php

It probably does, maybe it assigns numerical indexes to each array entry and cycles through the array again? I have no idea, If I had to guess it gets into "C pointers" and stuff...

http://pweb.netcom.com/~tjensen/ptr/ch1x.htm (http://pweb.netcom.com/%7Etjensen/ptr/ch1x.htm)

I don't know alot about it... but a really good website to learn is Daimonin.net . They are completely open source, and instead of running PHP as a scripting extension they run LUA. I learned alot from them... Hope that helps...

weegillis
06-16-2010, 05:04 AM
Before this gets way over my head... Very interesting reading MrGamm. kgun, C may be the way to go for an enterprise project, but the level I work at and the size of the project dictates, "The most with the least." I'm still a long way off regarding a web page as anything more than a linear procedure. All my databases are built around CSV and PHP tables, and never exceed more than a few dozen (or hundred) rows.

I am an HTML coder looking for faster, better ways to get the work done with the greatest consistency and uniformity, yet with a level of customization. I've only recently found some favor in PHP, since it relieved me of the tedium of editing dozens (or hundreds) of pages when there is a change in site header, footer or links. Silly me, this took years to catch on to!

Recently I lost my flagship PHP project due to budget cuts, and consequently a good lot of my working code is without a test bed and is laying idle. Much as I like to theorize, my main mission is live working code, so I work live. I do still have a smidgen of PHP in my other sites, but only one (besides the one in this example) is nearly 100% PHP driven. I have yet to venture into MySQL. It's a big leap, and I want to be sure of the fundamentals before going to the next step.

MrGamm, the Pointers are the thing. Wrapping my head around how to most simply point to the things that I want to hi-lite, based on their query, and fit them into the loading page (or perhaps AJAX at some point) is my only objective. I'm content to let C do what C does, as long as PHP will let me do what I want to do, C concerns aside. If my script fails, it fails. If it runs, it should run right, as in correctly, and fast, as in efficiently.

I can only measure efficiency based on reasoning, and have reasoned that the more tokens or reserved words in a statement, especially in an interpreted language as kgun pointed out earlier the more load on the server. One can reason that any little thing added to a statement can inflate the resource requirements logarithmically if it involves more pointers. Consider, for instance, AS. How much more CPU load does that one reserved word add? It is a dynamic pointer, is it not? And assuming there is a copying process that duplicates an array for the purposes of FOREACH, well that is plainly going to add to the load, and the time, no matter how freed up the CPU is, since each iteration through an array is indexed to a new object, which is itself a pointer to another object.

But I suppose the question ought to be, which is more OBJECT ORIENTED? Should I be thinking less of server load, and more of making objects more clearly defined, and take the hit on speed? Up to this point, I have treated everything as a procedure (with OOP in the back of my mind, not fully understood) which goes inline with my rationalizing web page generation as a linear process, with a start and finish.

FOREACH, as MrGamm has said, is just so convenient, with all the power of FOR and DO WHILE without the primitiveness; and, it is more descriptive and clearly defined in that DO WHILE is stipulated, as in DO WHILE not EOF or until BREAK. It contains its own pointers and counters.

MrGamm
06-16-2010, 05:42 AM
Lets say you have...

array('a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e')

You can't use for() anyways right?

It's not a huge server hit... just try not to loop through items excessively. Years ago when I was learning I used to do nested loops, upto 3 or 4 levels deep... eventually I realized that if I didn't have it down to a single loop or at max a double loop or so, then I messed up my data structure... I don't think you have too much to worry about. Why not go for PHP certification or something if it worries you?

kgun
06-16-2010, 08:54 AM
I have yet to venture into MySQL. It's a big leap, and I want to be sure of the fundamentals before going to the next step.
This is not that difficult. You need to connect to a database and populate tables with data. You should know something about relational database management systems to construct your tables properly. And since you are concerned about efficiency, you should learn to index tables and optimize databases. In OOP, you make your classses / objects and set up relations from the database to propertiess in your objects - object relational mapping. This can seem abstract before you start to study the subject. You can divide a page in three parts, header, footer and body. These elements can be stored in a database and manipulated via DOM objects and a MVC driven template engine.



MrGamm, the Pointers are the thing. Wrapping my head around how to most simply point to the things that I want to hi-lite, based on their query, and fit them into the loading page (or perhaps AJAX at some point) is my only objective. I'm content to let C do what C does, as long as PHP will let me do what I want to do, C concerns aside. If my script fails, it fails. If it runs, it should run right, as in correctly, and fast, as in efficiently.
Object oriented programming without pointers is like a regatta without wind. Object oriented programming is best suited to build frameworks and applications. You abstract away features to interfaces and make them more specific via inheritance. C is good for number crunching and looping through millions of items.



I can only measure efficiency based on reasoning, and have reasoned that the more tokens or reserved words in a statement, especially in an interpreted language as kgun pointed out earlier the more load on the server. One can reason that any little thing added to a statement can inflate the resource requirements logarithmically if it involves more pointers. Consider, for instance, AS. How much more CPU load does that one reserved word add? It is a dynamic pointer, is it not? And assuming there is a copying process that duplicates an array for the purposes of FOREACH, well that is plainly going to add to the load, and the time, no matter how freed up the CPU is, since each iteration through an array is indexed to a new object, which is itself a pointer to another object.

This is about caching and memory management, streamed parsers that load chunks of data instead of the whole data structure into memory etc. If you have extremely large tables this



Since that thread also mention the Oracle database platform, in an Oracle database you can categorize data as:



Active and hot (http://www.webproworld.com/webmaster-forum/threads/101705-Non-linear-time-signals-in-search-engine-algorithms.?p=515535&viewfull=1#post515535).
Less active.
Historical.
Archive.


By effective storage optimization like compressing archived data in the Oracle database archive, splitting partitioned tables across several servers (also possible in PostGreSQL (http://archives.postgresql.org/pgsql-performance/2006-02/msg00274.php)) using Flash cache etc. storage requirements in the hot and less active category can be reduced by 99%)

This can be important for the online part of a big news service.
Source: http://www.webproworld.com/webmaster-forum/threads/95191-The-death-of-newspapers-...?p=515820&viewfull=1#post515820

cite should indicate what is possible.



But I suppose the question ought to be, which is more OBJECT ORIENTED? Should I be thinking less of server load, and more of making objects more clearly defined, and take the hit on speed? Up to this point, I have treated everything as a procedure (with OOP in the back of my mind, not fully understood) which goes inline with my rationalizing web page generation as a linear process, with a start and finish.

Object orientation implies overhead but in web applications where the document object model (DOM) and the XMLHttpRequest object (http://www.w3.org/TR/XMLHttpRequest/) for AJAX web applications are so important, you need to learn object oriented programming if you intend to do (some of) the work yourself and not rely solely on existing Blog, CMS and eCommerce platforms.



FOREACH, as MrGamm has said, is just so convenient, with all the power of FOR and DO WHILE without the primitiveness; and, it is more descriptive and clearly defined in that DO WHILE is stipulated, as in DO WHILE not EOF or until BREAK. It contains its own pointers and counters.
This is cosmetics.

Conclusion.


There are online resources like W3Schools where you can also certifie yourself.
I will recommend the following books in order from simple to advanced:
- Jason Lengstorf "PHP for Absolute beginners" Apress. You also learn to work with PHP and the MySQL database platform in making your own blog.
- Larry Ullman "PHP 6 and MySQL 5". Peachpit Press. The best book of these IMO.
- Thompson, Nowicki and Meyer: "Professional PHP 6". Wrox Professional and you learn the compact Ulysses framework, object relational mapping and object overloading. You learn to work with the PostGreSQL databae platform. The preferred free database platform among many professionals. In addition you learn how to make portable database applications with the PDO data base object.
- Michael Peacock "PHP 5 e-commerce Development". Packt Publishing. The code do not function, but if you understand it you will learn three simple design patterns, MVC, registry and singleton. You should at this level be able to fix the code and understand how you make your own framework. Study the text and fix the code if you have time.
- Robert Richards "Pro PHP XML and Web services" Apresss

Bolded words = Search engine queries.