Avoid deep nesting code in grouping logic - php

I need some advice or recommended practices here.
I have a multiple field (six or more) group by SQL query. I'm getting the expected results in the right order.
My default approach to this is to iterate over the ordered results saving the last loop element to test it on next iteration. If it changed then I add it to the resulting list and move on. I think this is a common way to solve this kind of problem.
Up to two fields the I think my approach is fine. But when I group by more than two fields it seems overcomplicated. The code begins to rot and looks difficult to maintain as the number of nested conditions grows.
Is there a better way at all to accomplish this?
My default approach (one field)
$groupOne = null;
$lastId = null;
$result = array();
foreach($orderedData as $item) {
if ($lastId !== $item['id']) {
if ($groupOne !== null) {
$resultList[] = $groupOne;
}
$groupOne = new stdClass();
}
//rest of the logic
$lastId = $item['id'];
}

Actually, I found a better way. In the beginning of loop instead of validating all the group breaks I just validate the last one. If the last one changed then it's logical that all other ones before must be updated too. This simplifies my code. But I'm always open to suggestions and other examples. Thanks.

Related

Is there a way to reduce multiple comparison with similar parameters?

I am using php as backend of a website. I made a form of around 50 questions and I have to store it in a table every single time I answer something different.
So my first newbie thought was to compare the $request->Question1 with the $table->Question1 and if this is different, I create a new record on the History table.
But it took my to an endless and nothing good looking comparison lines, repeating some of the code like:
if ($table->Question1 != $request->Question1)
{
$Question = new HistoryTable();
$Question ->reason = 'Change Answer';
$Question ->column_affected = 'Question1';
$Question ->old_value = $table->Question1;
$Question ->new_value = $request->Question1;
$Question ->created_at = Carbon::now();
$Question ->save();
}
Is there a way it could be reduced ? I was thinking in using a form, but I have to mention I have columns/values as Question23_1 and Question23_2 ... but they are the same name as in table
Thanks in advance!
Well, some might suggest a different database-table architecture – one that does not involve these "repeating groups." But there might be other compelling reasons to have done what you did.
Maybe you could retrieve the record, instead of as a "PHP object," as an array ("hash" ...) indexed by field-name. Then you could use interpolation of strings such as "Question$x_$y" ... substituting the values of $x and $y to obtain the name of the field whose value you are now interested in ...

Processing multidimensional csv-originated arrays in PHP

Within the first column of every row lies a position, i.e. Software Engineer, and if the user's position matches the one in that row, the nested for loop should check in each column of that row if the given id exists in the csv string for that column. I haven't worked much with arrays in PHP and most of my experience with multidimensional arrays lies within Java so pardon my java-themed PHP code:
$csv = read_csv('/filepath/tct.csv');
$csv_rows = 75;
for($i=1;$i<$csv_rows;$i++)
{
if(strtolower($user['user_pos']) == strtolower($csv[$i][0]))
{
for($j=1;j<sizeof($csv[$i]);j++)
{
if(array_search($user['id'], explode(",",$csv[$i][$j])))
{
return true;
}
}
}
}
Unfortunately, my java doesn't seem to work and all of the existing questions concerning PHP multidimensional arrays only confuse me with the $key->$value talk. Can anyone explain to me what I need to do adjust to get this to work?
So what I was doing is a perfectly acceptable (in terms of functionality) when processing multidimensional arrays, I just neglected to place the $ before j twice in the inner loop.
The most efficient and understandable way I've found thus far is:
foreach($csv as $csv_row) {
for($i=1;$i<count($csv_row);$i++) {
//do something with $csv_row[$i]
}
}
The standard-issue nested for loop is to ensure the row names aren't iterated over since I always had row names at column[0] (despite the fact that the outer foreach will loop over the column names in row 0)
Of course, this is heavily reliant on someone using the same spreadsheet/csv layout. If it's a csv of just data, I'm sure the inner loop could be changed to:
foreach($csv_row as $csv_col {
//do something with $csv_col
}

for loop vs while loop vs foreach loop PHP

1st off I'm new to PHP. I have been using for loop,while loop,foreach loop in scripts. I wonder
which one is better for performance?
what's the criteria to select a loop?
which should be used when we loop inside another loop?
the code which I'm stuck with wondering which loop to be used.
for($i=0;$i<count($all);$i++)
{
//do some tasks here
for($j=0;$j<count($rows);$j++)
{
//do some other tasks here
}
}
It's pretty obvious that I can write the above code using while. Hope someone will help me out to figure out which loop should be better to be used.
which one is better for performance?
It doesn't matter.
what's the criteria to select a loop?
If you just need to walk through all the elements of an object or array, use foreach. Cases where you need for include
When you explicitly need to do things with the numeric index, for example:
when you need to use previous or next elements from within an iteration
when you need to change the counter during an iteration
foreach is much more convenient because it doesn't require you to set up the counting, and can work its way through any kind of member - be it object properties or associative array elements (which a for won't catch). It's usually best for readability.
which should be used when we loop inside another loop?
Both are fine; in your demo case, foreach is the simplest way to go.
which one is better for performance?
Who cares? It won't be significant. Ever. If these sorts of tiny optimizations mattered, you wouldn't be using PHP.
what's the criteria to select a loop?
Pick the one that's easiest to read and least likely to cause mistakes in the future. When you're looping through integers, for loops are great. When you're looping through a collection like an array, foreach is great, when you just need to loop until you're "done", while is great.
This may depend on stylistic rules too (for example, in Python you almost always want to use a foreach loop because that's "the way it's done in Python"). I'm not sure what the standard is in PHP though.
which should be used when we loop inside another loop?
Whichever loop type makes the most sense (see the answer above).
In your code, the for loop seems pretty natural to me, since you have a defined start and stop index.
Check http://www.phpbench.com/ for a good reference on some PHP benchmarks.
The for loop is usually pretty fast. Don't include your count($rows) or count($all) in the for itself, do it outside like so:
$count_all = count($all);
for($i=0;$i<$count_all;$i++)
{
// Code here
}
Placing the count($all) in the for loop makes it calculate this statement for each loop. Calculating the value first, and then using the calculation in the loop makes it only run once.
For performance it does not matter if you choose a for or a while loop, the number of iterations determine execution time.
If you know the number of iterations at forehand, choose a for loop. If you want to run and stop on a condition, use a while loop
for loop is more appropriate when you know in advance how many
iterations to perform
While loop is used in the opposite case(when you don't know how many
iterations are needed)
For-Each loop is best when you have to iterate over collections.
To the best of my knowledge, there is little to no performance difference between while loop and for loop i don't know about the for-each loop
Performance:
Easy enough to test. If you're doing something like machine learning or big data you should really look at something that's compiled or assembled and not interpreted though; if the cycles really matter. Here are some benchmarks between the various programming languages. It looks like do-while loop is the winner on my systems using PHP with these examples.
$my_var = "some random phrase";
function fortify($my_var){
for($x=0;isset($my_var[$x]);$x++){
echo $my_var[$x]." ";
}
}
function whilst($my_var){
$x=0;
while(isset($my_var[$x])){
echo $my_var[$x]." ";
$x++;
}
}
function dowhilst($my_var){
$x=0;
do {
echo $my_var[$x]." ";
$x++;
} while(isset($my_var[$x]));
}
function forstream(){
for($x=0;$x<1000001;$x++){
//simple reassignment
$v=$x;
}
return "For Count to $v completed";
}
function whilestream(){
$x=0;
while($x<1000001){
$v=$x;
$x++;
}
return "While Count to 1000000 completed";
}
function dowhilestream(){
$x=0;
do {
$v=$x;
$x++;
} while ($x<1000001);
return "Do while Count to 1000000 completed";
}
function dowhilestream2(){
$x=0;
do {
$v=$x;
$x++;
} while ($x!=1000001);
return "Do while Count to 1000000 completed";
}
$array = array(
//for the first 3, we're adding a space after every character.
'fortify'=>$my_var,
'whilst'=>$my_var,
'dowhilst'=>$my_var,
//for these we're simply counting to 1,000,000 from 0
//assigning the value of x to v
'forstream'=>'',
'whilestream'=>'',
'dowhilestream'=>'',
//notice how on this one the != operator is slower than
//the < operator
'dowhilestream2'=>''
);
function results($array){
foreach($array as $function=>$params){
if(empty($params)){
$time= microtime();
$results = call_user_func($function);
} elseif(!is_array($params)){
$time= microtime();
$results = call_user_func($function,$params);
} else {
$time= microtime();
$results = call_user_func_array($function,$params);
}
$total = number_format(microtime() - $time,10);
echo "<fieldset><legend>Result of <em>$function</em></legend>".PHP_EOL;
if(!empty($results)){
echo "<pre><code>".PHP_EOL;
var_dump($results);
echo PHP_EOL."</code></pre>".PHP_EOL;
}
echo "<p>Execution Time: $total</p></fieldset>".PHP_EOL;
}
}
results($array);
Criteria: while, for, and foreach are the major control structures most people use in PHP. do-while is faster than while in my tests, but largely underused in most PHP coding examples on the web.
for is count controlled, so it iterates a specific number of times; though it is slower in my own results than using a while for the same thing.
while is good when something might start out as false, so it can prevent something from ever running and wasting resources.
do-while at least once, and then until the condition returns false. It's a little faster than a while loop in my results, but it's going to run at least once.
foreach is good for iterating through an array or object. Even though you can loop through a string with a for statement using array syntax you can't use foreach to do it though in PHP.
Control Structure Nesting: It really depends on what you're doing to determine while control structure to use when nesting. In some cases like Object Oriented Programming you'll actually want to call functions that contain your control structures (individually) rather than using massive programs in procedural style that contain many nested controls. This can make it easier to read, debug, and instantiate.

PHP Change Array Over and Over

I have any array
$num_list = array(42=>'0',44=>'0',46=>'0',48=>'0',50=>'0',52=>'0',54=>'0',56=>'0',58=>'0',60=>'0');
and I want to change specific values as I go through a loop
while(list($pq, $oin) = mysql_fetch_row($result2)) {
$num_list[$oin] = $pq;
}
So I want to change like 58 to 403 rather then 0.
However I always end up getting just the last change and non of the earlier ones. So it always ends up being something like
0,0,0,0,0,0,0,0,0,403
rather then
14,19,0,24,603,249,0,0,0,403
How can I do this so it doesn't overwrite it?
Thanks
Well, you explicititly coded that each entry should be replaced with the values from the database (even with "0").
You could replace the values on non-zero-values only:
while(list($pq, $oin) = mysql_fetch_row($result2)) {
if ($pq !== "0") $num_list[$oin] = $pq;
}
I don't get you more clear, i thought your asking this only. Check this
while(list($pq, $oin) = mysql_fetch_row($result2)) {
if($oin==58) {
$num_list[$oin] = $pq;
}
}
In my simulated tests (although You are very scarce with information), Your code works well and produces the result that You want. Check the second query parameter, that You put into array - namely $pg, thats what You should get there 0,0,0,0,0...403 OR Other thing might be that Your $oin numbers are not present in $num_list keys.
I tested Your code with mysqli driver though, but resource extraction fetch_row is the same.
Bear in mind one more thing - if Your query record number is bigger than $numlist array, and $oin numbers are not unique, Your $numlist may be easily overwritten by the folowing data, also $numlist may get a lot more additional unwanted elements.
Always try to provide the wider context of Your problem, there could be many ways to solve that and help would arrive sooner.

PHP Compare Two Arrays?

I'm trying to compare two entries in a database, so when a user makes a change, I can fetch both database entries and compare them to see what the user changed, so I would have an output similar to:
User changed $fieldName from $originalValue to $newValue
I've looked into this and came across array_diff but it doesn't give me the output format I need.
Before I go ahead and write a function that does this, and returns it as a nice $mtextFormatDifferenceString, can anyone point me in the direction of a solution that already does this?
I don't want to re-invent the wheel..
Since you require "from $originalValue to $newValue", I would go ahead and select the two rows, put them in assoc arrays, then foreach through the keys, saving the ones that aren't equal. Kind of like:
$fields = array_keys($row1);
$changedFields = array();
foreach ($fields as $field) {
if ($row1[$field] != $row2[$field]) {
$changedFields[] = $field;
}
}
I realize you were asking about the existence of pre-built wheels but I felt the solution was pretty simple.
?>
Although you didn't define what format you needed, but well-known diff algorithm is probably for you. Google for PHP diff algorithm and you'll find some suggestions I am sure.
You could get the changed values ($newValue) with array_diff_assoc and then just use the keys ($fieldName) to find the original value $originalValue and output it in anyformat you want

Categories