0

I am creating a conversion table using PHP and I have to check the user's input against A LOT of scenarios and I started by using if statements but this doesn't seem to be efficient whatsoever and I was hoping for an easier way to go through all the scenarios.

I looked into ternary and switch options but those don't seem to do what I need it to do and I also considered array's (the option I think I need to use)

What I'm trying to do: The user enters in a grade level and scores for a category. Based on the sum of those scores and the grade level, I need to compare them to get two other scores Example code:

if ($grade == 1  && $sumScore <= 5)
 {
   $textscore = 'Beginning';
 }
 if ($grade ==1 && ($sumScore>5 && $sumScore <=8)) 
  {
   $textScore = 'Intermediate';
  }

etc....

There are 13 grades (K-12) and 4 categories I need to go through all with their own "raw scores" to consider to get these other scores. How can I avoid using a ton of If/Else if statements?

Thanks!!

Kayla
  • 19
  • 4
  • 1
    at first, show those `13 grades and 4 categories` descriptions with their interrelations – RomanPerekhrest Apr 23 '16 at 20:44
  • What kind of logic do you need? Is it always ($grade < X && $sumScore <= Y) or could it be something else? – Bob Salmon Apr 23 '16 at 20:46
  • **etc...** Not very helpful. If you show all your IF code we can see what need to be done and suggest better/other ways of doing it – RiggsFolly Apr 23 '16 at 20:46
  • The logic is pretty consistent like the example I provided. They all have their own raw score table that has additional scores that are correlated. And the raw scores can vary depending on the grade level. – Kayla Apr 23 '16 at 20:54
  • @Kayla, Block whole condition statement on your IDE/Text Editor there, use `ctrl+c` or right click and copy then click edit post and paste the code inside code section within your question :) – Hendra Nucleo Apr 23 '16 at 20:57
  • A bitmask might be what you're looking for. See this thread here on SO: http://stackoverflow.com/questions/11880360/how-to-implement-a-bitmask-in-php – Jan Apr 23 '16 at 20:59
  • 1
    You are not providing enough information for a proper answer. It is possible that you can just use a mathematical formula to arrive at the answer, but with only providing two of the many possible scenarios. – kojow7 Apr 23 '16 at 21:04
  • A smal tip is to use elseif instead. That can shorten it slightly. This row can be shrunk to: elseif ($grade ==1 && $sumScore <=8) because now you already know that it was not less than 5 as in the previous if. But we need to see more to know how to shorten it even more – Andreas Apr 23 '16 at 21:14
  • What is the highest possible sum of scores? What is the number of different possible outcomes (levels)? Could you not provide the complete 13 x 4 table? That would clarify a lot. You also say you need to calculate two scores, but your code sample only shows how you derive *$textscore*. – trincot Apr 23 '16 at 21:16

3 Answers3

2

You could use a two-dimensional array that's 13x4. Then you can use a nested for loop to go through each possibility and just have one statement that gets run a bunch of times because of the for loops.

For example, the array might look like this:

$textscores = array (
  1 => array(5 => 'Beginning', 8 => 'Intermediate', ...),
  ...
  3 => array(5 => 'Intermediate', ...),
  ...
);

The nested for loop might look like this:

foreach($textscores as $grade => $scores) {
  foreach($scores as $sumScore => $textScore) {
    if($userGrade == $grade &&  $userSumScore <= $sumScore) {
      $userTextScore = $textScore;
      break 2;
    }
  }
}
Nathan Bierema
  • 1,813
  • 2
  • 14
  • 24
  • Depending on the grade level, it's different. For example, grade 1 can have a "raw score" of 5 and be "beginning", but for grade 3, a "raw score" of 5 can be "intermediate." That's why I need to know which grade level they are. – Kayla Apr 23 '16 at 20:57
  • Yeah, you have a different row for each grade level. I'll expand the example. – Nathan Bierema Apr 23 '16 at 20:58
  • I added an example for loop. – Nathan Bierema Apr 23 '16 at 21:07
  • I used this and tweaked the code a bit to match what I already had and it works like a charm! You are simply the best. :D – Kayla Apr 23 '16 at 21:22
0

I haven't tested this (sorry), but I think something like this

function getTextScore($grade, $sum) {

    $rules = array( array("grade" => 1, "minSum" => null, "maxSum" => 5, "textScore" => "Beginning"),
                    array("grade" => 1, "minSum" => 6, "maxSum" => 8, "textScore" => "Intermediate" ),

                /* ... */
                );


    for ($ruleIdx=0; $ruleIdx<count($rules); $ruleIdx++) {

        $currentRule = $rules[$ruleIdx];

        if (($currentRule['grade'] == $grade) &&
            ((is_null($currentRule['minSum'])) || ($currentRule['minSum'] <= $sum)) &&
            ((is_null($currentRule['maxSum'])) || ($currentRule['maxSum'] >= $sum))) {
            return $currentRule['textScore'];
        }
    }

    // got to the end without finding a match - need to decide what to do
}

The rules have optional min and max values. It will stop as soon as it finds a match, so the order is important. You will need to decide if no rules are matched. You should be able to just drop extra rules in or change the existing ones without changing the logic.

Bob Salmon
  • 411
  • 4
  • 10
0

From your example I would suggest the following

Multidimensional array, but a bit different from the way you construct the array

// Grade => [Text => [Min,Max]]
$textScores = [
    1 => [
        'Beginning'    => [0, 5],
        'Intermediate' => [5, 8],
        'Master'       => [8, 10]
    ],
    2 => [
        'Beginning'    => [0, 7],
        'Intermediate' => [7, 8],
        'Master'       => [8, 10]
    ],
    3 => [
        'Beginning'    => [0, 3],
        'Intermediate' => [3, 6],
        'Master'       => [6, 10]
    ]
];

// Random input to test
$grade    = rand(1, 3);
$sumScore = rand(0, 10);

foreach ($textScores[$grade] as $Text => $MinMax) {

    if ($MinMax[0] <= $sumScore && $MinMax[1] >= $sumScore) {
        $textScore = $Grade;
        break;
    }
}
David Lavieri
  • 1,060
  • 1
  • 8
  • 19
  • this is also very useful. I think I might look into this one so I don't have to write out each raw score and their text score. – Kayla Apr 23 '16 at 21:38
  • I actually used this method. This reduces my code a lot. I actually made a another array with the sum values instead of using you min/max method and then just added another foreach loop. – Kayla Apr 23 '16 at 21:54
  • I would like to see that code, seems interesting. I love arrays :) – David Lavieri Apr 23 '16 at 22:06