| Simplifying complex if/else statements
|
ocon

msg:4506187 | 10:22 pm on Oct 9, 2012 (gmt 0) | 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?
|
swa66

msg:4506378 | 9:56 am on Oct 10, 2012 (gmt 0) | 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; }
|
|
|
Dinkar

msg:4507518 | 5:00 pm on Oct 12, 2012 (gmt 0) | 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; }
|
vincevincevince

msg:4514514 | 5:49 am on Nov 1, 2012 (gmt 0) | 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.
|
lucy24

msg:4514824 | 10:06 pm on Nov 1, 2012 (gmt 0) | 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 ::
|
vincevincevince

msg:4514871 | 12:15 am on Nov 2, 2012 (gmt 0) | 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.
|
lucy24

msg:4514953 | 7:23 am on Nov 2, 2012 (gmt 0) | ... 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.
|
vincevincevince

msg:4515083 | 3:39 pm on Nov 2, 2012 (gmt 0) | Ah yes, sorry - my confused mistake
|
jadebox

msg:4516834 | 6:14 pm on Nov 7, 2012 (gmt 0) | | :: 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 ... }
|
lucy24

msg:4516895 | 10:15 pm on Nov 7, 2012 (gmt 0) | Oh, gosh, can you do that? :: woo hoo ::
|
jadebox

msg:4517311 | 9:48 pm on Nov 8, 2012 (gmt 0) | "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.
|
jadebox

msg:4517313 | 9:56 pm on Nov 8, 2012 (gmt 0) | 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.
|
penders

msg:4517870 | 12:20 am on Nov 11, 2012 (gmt 0) | 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
|
|
|