Welcome to WebmasterWorld Guest from 54.146.171.44

Forum Moderators: coopster & jatar k

Message Too Old, No Replies

Simplifying complex if/else statements

   
10:22 pm on Oct 9, 2012 (gmt 0)

5+ Year Member Top Contributors Of The Month



Sometimes I find myself needing to test for:

if($a<15 && $b<1.2){Scenario A;}
else if($a<23 && $b<2.6){Scenario B;}
else if($a<36 && $b<3.4){Scenario C;}
else{do Scenario D;}

Other times I need to test for:

if($a<23 && $b<2.6){Scenario B;}
else if($36 && $b<3.4){Scenario C;}
else{Scenario D;}

And still, sometimes I need to test for:

else if($36 && $b<3.4){Scenario C;}
else{Scenario D;}

In total there are 8 different scenarios that I need to test for in each item inside an array loop. Before I would test for each scenario individually, but that added up quickly for large arrays. Then I realized I could run a simple test once before the loop and find out which subset of specific scenarios I need to test for inside the loop; reducing the number of tests from 8 to maybe just 2.

Lets say I need to test for scenarios ABC&D, other times BC&D, C&D, EF&G, F&G, and sometimes I know right away its H.

How could I structure the inside of my loop so I don't need to test each scenario individually (like I'm doing now) or without having to repeat the lines of test code over and over?
9:56 am on Oct 10, 2012 (gmt 0)

WebmasterWorld Senior Member swa66 is a WebmasterWorld Top Contributor of All Time 10+ Year Member



There's one thing about else if vs. elseif. Although in PHP they are mostly the same. But I've never felt comfortable with leaving the curly braces off of a branch as the else if is actually doing.

Ref: [php.net...]

With the kind of tests you have it might be hard to use, but there's also the switch statement in PHP.

Ref: [php.net...]


So maybe you need once to determine the scenario you're in, store the scenario in a variable and then use switch statements from there on.

Ref: [php.net...]


Something like:


if ($a<15 && $b<1.2) {
$scenario='A';
} elseif ($a<23 && $b<2.6) {
$scenario='B';
} elseif ($a<36 && $b<3.4) {
$scenario='C';
} else {
$scenario='D';
}

//And then where you need it:

switch ($scenario) {
case 'A':
echo 'executing A';
break;
case 'B':
echo 'executing B';
break;
default:
echo 'executing other scenario';
break;
}
5:00 pm on Oct 12, 2012 (gmt 0)

10+ Year Member



If I understood your question, the solution may be to create functions for each scenario

function scenario A
function scenario B
function scenario C
function scenario D
etc etc

Then call those function as required

switch ($scenario) {
case 'AB':
function scenario A;
function scenario B;
break;
case 'BHC':
function scenario B;
function scenario H;
function scenario C;
break;
default:
function scenario default;
break;
}
5:49 am on Nov 1, 2012 (gmt 0)

WebmasterWorld Senior Member vincevincevince is a WebmasterWorld Top Contributor of All Time 10+ Year Member



The other way:


$data=... your data;
$scenarios=NULL Array() of same size (I assume a 1D array here)
//first test
foreach ($data as $pointer=>$datum)
{
if ($scenarios[$pointer]!==NULL) continue;
if (testA($datum)) $scenarios[$pointer]="A";
}
//second test
foreach ($data as $pointer=>$datum)
{
if ($scenarios[$pointer]!==NULL) continue;
if (testB($datum)) $scenarios[$pointer]="B";
}
//third test
foreach ($data as $pointer=>$datum)
{
if ($scenarios[$pointer]!==NULL) continue;
if (testC($datum)) $scenarios[$pointer]="C";
}
//final test
foreach ($data as $pointer=>$datum)
{
if ($scenarios[$pointer]!==NULL) continue;
$scenarios[$pointer]="D"; //catch all
}


The basic approach is to loop the $data repeatedly, each time only testing those $data points which have not yet been assigned a $scenario. Put in the tests which will recognise the largest number first.

If you were careful, you could depopulate (unset()) $data points as you go and so automatically skip the records you know about. Be careful you don't accidentally re-index the array in your work though. That would avoid the NULL check.
10:06 pm on Nov 1, 2012 (gmt 0)

WebmasterWorld Senior Member lucy24 is a WebmasterWorld Top Contributor of All Time Top Contributors Of The Month



More information!

When you say "array loop" do you mean that where your example has $a and $b it's really something like $a[0], $a[1], $a[2] and so on up to $a[googol]? Do the terms always come in pairs, like $a[0] with $b[0] and so on? Are they constant? That is: they're variables, duh, but does their value change in the course of the code? Are your consecutive tests always nested as in your example, so anything that meets test 3 (< some number) automatically meets test 2 (< some smaller number)?

All the questions are because I'm thinking along the lines of taking the if/then material and putting it right into the array itself. That is: run the test once, and set $c() based on its results.

The code itself is then structured as a "switch" on $c[your-current-number], with
case x: blahblah;
case y: blahblah;
case z: blahblah;
OR, elsewhere,
case x: case y: blahblah;
case z: blahblah;
depending on how many scenarios you're using for that specific function.

But that's based on assumptions about your overall pattern that may not be valid in the first place.

:: thinking longingly of Basic dialect that let you use "case" without an argument ::
12:15 am on Nov 2, 2012 (gmt 0)

WebmasterWorld Senior Member vincevincevince is a WebmasterWorld Top Contributor of All Time 10+ Year Member



Hi Lucy, I had assumed from your talk of 'large arrays' that you were trying to process large arrays of data to find the scenarios. Perhaps I have got it wrong!

By array loop, I meant only to have the data in an array, and then loop through the array. The matching $scenarios array would be of the same size, and used for storing data about scenarios already identified.

The 'nesting' in my example would need careful arrangements of tests.
7:23 am on Nov 2, 2012 (gmt 0)

WebmasterWorld Senior Member lucy24 is a WebmasterWorld Top Contributor of All Time Top Contributors Of The Month



... and when you say "Lucy" you mean "ocon" (the OP, the guy with the problem). A simple transposition, a mere matter of cat walking across keyboard...

Oh, and conversely when I say "you" in the previous post, I also mean the OP, not, er, you. Even if you're both talking about arrays.

And, uhm, as long as I'm here. When I say
anything that meets test 3 (< some number) automatically meets test 2 (< some smaller number)

I mean, of course,
anything that meets test 2 (< some number) automatically meets test 3 (< some larger number)


I've really got to stop relying on the cat to proofread my posts.
3:39 pm on Nov 2, 2012 (gmt 0)

WebmasterWorld Senior Member vincevincevince is a WebmasterWorld Top Contributor of All Time 10+ Year Member



Ah yes, sorry - my confused mistake
6:14 pm on Nov 7, 2012 (gmt 0)

10+ Year Member



:: thinking longingly of Basic dialect that let you use "case" without an argument ::


Do you mean something like this?


switch (true)
{
case ($a < 15 && $b < 1.2):
doScenarioA();
break;
case ($a < 23 && $b < 2.6):
doScenarioB();
break;
' ... and so on ...
}
10:15 pm on Nov 7, 2012 (gmt 0)

WebmasterWorld Senior Member lucy24 is a WebmasterWorld Top Contributor of All Time Top Contributors Of The Month



Oh, gosh, can you do that?

:: woo hoo ::
9:48 pm on Nov 8, 2012 (gmt 0)

10+ Year Member



"Oh, gosh, can you do that?"

Yep. As in the example, using SWITCH like that can result in cleaner code than using IF followed by a bunch of ELSE IFs.
9:56 pm on Nov 8, 2012 (gmt 0)

10+ Year Member



As an aside ... the "switch(true)" thing works in PHP because PHP implements the case structure as a series of IFs. PHP compares the switch value to each case expression until one matches.

Other languages use the "switch" value as an index into a table. Only the switch value is determined at run time. This allows the compiled code to quickly jump to the matching case. In those languages, the switch structure is much more efficient. But it's not as flexible since the case values have to be constants.
12:20 am on Nov 11, 2012 (gmt 0)

WebmasterWorld Senior Member penders is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month



Perhaps...

// Declare scenarios (A..H = 8) 
$scenarios = array (
'A' => array (15, 1.2), // $a, $b
'B' => array (23, 2.6),
'C' => array (36, 3.4),
// D, E, F, G and H
);

// Example data (large array)
$data = array (
array (10, 1.8), // $a, $b
array (24, 3.0),
array (40, 2.3),
// etc.
);

// Run test to determine which subset of scenarios to test for
// - based on $data
$scenariosToTest = 'ABCD';
$lastScenarioId = $scenariosToTest[strlen($scenariosToTest)-1];

// Step through data and check scenarios
foreach ($data as $row) {
// Step through scenarios to test (subset)
foreach (str_split($scenariosToTest) as $scenarioId) {
// Reached last scenario to test? (ELSE)
// Could combine into check below or omit entirely and allow to fall through if it fails
if ($scenarioId == $lastScenarioId) {
break;
}

// $row[0] is $a / $row[1] is $b from OP's example
if (($row[0] < $scenarios[$scenarioId][0]) && ($row[1] < $scenarios[$scenarioId][1])) {
break;
}
}
// Do something with resulting scenario A, B, C, etc.
echo $scenarioId;
}


Outputs: BCD
 

Featured Threads

Hot Threads This Week

Hot Threads This Month