More efficient way of performing multiple IFs - php

This is just a simple check to see what letter grade to output. Is there any faster and more efficient way to achieve the objective?
if ( $grade >= 90 ) {
echo "A";
} elseif ( $grade >= 80 ) {
echo "B";
} elseif ( $grade >= 70 ) {
echo "C";
} else {
echo "Failed."
}

This is not answering your actual question but I think you are making a mistake here:
You really shouldn't be thinking about efficiency when using PHP, it is not a language that was designed for speed, but one that was designed for ease of use. Even more so if your application is not yet finished and you haven't verified that this piece of code slows down your whole application (using the profiler of xdebug, for example).

Any such improvements would be micro-optimizations. I think you've got the best solution for both efficiency and clarity.

I agree with other posters that you're doing it right already. However, in situations like these you could could try converting the $grade to a value that could be used as an index in an associative array, not unlike what #ghostdog74 tried to do above.
$gradeindex = (int)$grade / 10; // 10 since we want 10-19 = 1, etc..
$gradenames = array('10' => 'A+', '9' => 'A', '8' => B, ..... );
However, since so many of them are identical, I'd probably use a switch()
$gradeindex = (int)$grade / 10; // 10 since we want 10-19 = 1, etc..
switch ($gradeindex) {
case 10:
case 9:
$gradename = 'A';
break;
case 8:
$gradename = 'B';
break;
case 7:
$gradename = 'C';
break;
default:
$gradename = 'Failed';
}
echo $gradename;
But as already said, you're basically best of with your current if statement.

I'm sure there are weird ninja ways to do what you're doing, but yours is certainly the best. It's the most clear to read, and performance wise it's too fast to matter.

Personally, I think I would use a function with multiple returns for this purpose:
function intGradeToStrGrade($grade) {
if ($grade >= 90) return "A";
if ($grade >= 80) return "B";
...
}
However, there has been some debate here on SO if multiple returns in one function are OK or not. Your choice. I think this is much cleaner than a drawn-out if statement.

I don't actually know what the efficiency of this is, but I saw this problem and wanted to solve it in a non-nested-if() style so more knowledgeable folk could compare it's relative efficiency. Soooooo... Here's and alternative way of going about it :)
function GetLetterForPercentGrade($grade)
{
$letter= chr(($grade >59) ? (10-floor($grade /10))+64 : 'F');
$sign = chr(abs((ceil(((($grade %10)*10)+1)/34)*34)-69)+10);
return $letter.$sign;
}

$grade=87;
$grades=array("A"=>range(95,100),"B"=>range(80,94),"C"=>range(70,79),"Failed"=>range(0,69));
foreach($grades as $g=>$v){
if ( in_array($grade,$v) ){
print $g."\n";
}
}

Related

How to check multiple comparisons in PHP not using an if or case?

So I know you could do something simple like this to set a variable equal to one thing if the condition is true and one thing if it is false.
$height > 70 ? $output = "Taller than 6 foot" : $output = "Shorter than 6 foot";
But how would I go through and check multiple things like this not using an if statement? For example, if I wanted to check if height was between 5 and 6, between 4 and 5, between 3 and 4 and more, and then only echo out one $result based on which category $height fell in, how would I do that? Could I just add something useless after the : such as a variable I would never use?
The only way to parameterize this would be to use switch which is mostly the same as using ifs but with a multiple verifications. Sadly, there's no shorter way to write this. (There might be, but they might be cumbersome to write / read which is not always an advantage!).
Here's a switch / case statement that uses multiple conditions. Usually, you pass the variable to the switch statement and you use the case statements with variables or possible values, but since the possible values are conditions, you need to pass true as a parameter as this is the value to be expected. You can reverse this by passing false if needed.
switch(true){
case ($my_number > 3):
echo "Greater than 3";
break;
case ($my_number <= 3):
echo "Smaller or equal to 3";
break;
}
you can make nested conditions:
$output = ($height < 6 && $height > 5) ? 'something' : (($height <= 3) ? 'less t. 3' : 'over 4')
but this is not really readable, I would avoid this, syntax with multiple conditions is better with if/switch

Conditional switch statements in PHP

I'm quite used to vb.net's Select Case syntax which is essentially a switch statement, where you can do things like Case Is > 5 and if it matches, it will execute that case.
How can I do what I'm going to call "conditional switch statements" since I don't know the actual name, in PHP?
Or, what's a quick way to manage this?
switch($test)
{
case < 0.1:
// do stuff
break;
}
That's what I've tried currently.
I think you're searching for something like this (this is not exactly what you want or at least what I understand is your need).
switch (true) finds the cases which evaluate to a truthy value, and execute the code within until the first break; it encounters.
<?php
switch (true) {
case ($totaltime <= 1):
echo "That was fast!";
break;
case ($totaltime <= 5):
echo "Not fast!";
break;
case ($totaltime <= 10):
echo "That's slooooow";
break;
}
?>
I tried to add this as a comment to the answer by BoltCock, but SO is telling me that his answer is locked so I'll make this a separate (and essentially redundant) answer:
The "switch(true)" answer from BoltCock is much like the following example, which although logically equivalent to if + else if + else is arguably more beautiful because the conditional expressions are vertically aligned, and is standard/accepted practice in PHP.
But the if + else if + else syntax is essentially universal across scripting languages and therefore immediately readable (and maintainable) by anyone, which gives it my nod as well.
There is an additional way you can accomplish this, in PHP 8.0+, by using a match statement.
If you have a single expression within each case, it is equivalent to the following match statement. Note that unlike switch statements, we can choose to return a variable (in this code I am storing the result in $result).
$test = 0.05;
$result = match (true) {
$test < 0.1 => "I'm less than 0.1",
$test < 0.01 => "I'm less than 0.01",
default => "default",
};
var_dump($result);
Match statements only allow you to have a single expression after each condition. You can work around this limitation by calling a function.
function tinyCase(){}
function veryTinyCase(){}
function defaultCase(){}
$test = 0.01;
match (true) {
$test < 0.1 => tinyCase(),
$test < 0.01 => veryTinyCase(),
default => defaultCase(),
};
And for reference, if you just want to check for equality you can do:
$result = match ($test) { // This example shows doing something other than match(true)
0.1 => "I'm equal to 0.1",
0.01 => "I'm equal to 0.01",
default => "default",
};
Match statements do have some key differences from switch statements that you need to watch out for:
My last example will use a strict equality check === instead of a loose one ==.
If a default case is not provided, an UnhandledMatchError error is thrown when nothing matches.
And there is no worrying about falling through to the next case if you forget to add break.
PHP supports switch statements. Is that what you wanted?
Switch statement with conditions
switch(true)
{
case ($car == "Audi" || $car == "Mercedes"):
echo "German cars are amazing";
break;
case ($car == "Jaguar"):
echo "Jaguar is the best";
break;
default:
echo "$car is Ok";
}

check that the value of a variable is in a particular range of values

First of all I want to say I am not a programmer but I have been playing around with some simple php scripts today and I have a quick question for those in the know. How could I simplify the following code so it does not use all of those OR logical operators?
$number = "";
if ("$number" == 2 || "$number" == 3 || "$number" == 8 || "$number" == 10)
{
echo ('Your number is ' . "$number");
}
Thanks,
Kris
<?php
if (in_array($number,array(2,3,8,10))) {
echo 'Your number is '.$number;
}
or
<?php
switch ($number) {
case 2:
case 3:
case 8:
case 10:
echo 'Your number is '.$number;
break;
case 99;
echo 'Your number is 99';
break;
}
Firstly, although quotations around your variables don't cause the code to break, you really really don't need them and in fact the only reason your code still works is because PHP has a strange system to match between strings and integers.
Anyway, one way to rewrite that code is as
$validNumbers = array(2,3,8,10);
if (in_array($number, $validNumbers))
{
echo ('Your number is '. $number);
}
Technically, you could also do
if ((1 << $number) & 1292)
if you're into unreadable code. This works because the binary representation of 1292 has a 1 exactly at the binary digits 2, 3, 8, and 10.
You can't make it simpler in a way that makes sense. I would keep it just like that.
EDIT: By "simplification" I would guess that you want to do less operations...
you could do this:
$valid_numbers = array(2, 3, 8, 10);
if (in_array($number, $valid_numbers)) {
echo 'Your number is ', $number;
}
p.s.: you don't need/it's wrong to put $number between quotes, since you're expecting an int.
hope this helps

PHP validation question

How do I check and see if a user enters only numbers and is at least 4 numbers long using PHP?
Mark Byers' suggestion is good, but here's another way:
$valid = ctype_digit($number) && strlen($number) >= 4;
You could use a regular expression:
/^\d{4,}$/
Example usage:
$s = "7325";
if (preg_match('/^\d{4,}$/', $s)) {
echo "matches";
}
ctype_digit() && strlen() wins
<?php
function benchmark($callback){
echo sprintf('%-30s: ', $callback);
$t = microtime(true);
foreach(range(1, 10000) as $n){
call_user_func($callback);
}
echo (microtime(true)-$t)."\n";
}
function mark_byers_preg_match(){
$s = "7325";
preg_match('/^\d{4,}$/', $s);
}
function notjim_ctype_digit_strlen(){
$number = 7325;
ctype_digit($number) && strlen($number) >= 4;
}
function tomalak_intval_broken(){
$check = 7325;
intval($check) == $check && $check >= 1000 && $check <= 9999;
}
benchmark('mark_byers_preg_match');
benchmark('notjim_ctype_digit_strlen');
benchmark('tomalak_intval_broken');
?>
results
mark_byers_preg_match : 0.029040098190308
notjim_ctype_digit_strlen : 0.026585817337036
tomalak_intval_broken : 0.019872903823853
Note: #Tomalak's does not work with numbers starting with 0 so it does not qualify
Edit: #kiethjgrant's solution was removed because intval(0000) evaluates as false when it should be true.
Do you have any example code to start with?
To strictly answer your question, you could use a regex like if(preg_match('/^\d{4,}$/', $input)....
But there's a lot more to consider here: you need to consider both validation and filtering (and you're best to keep the two separate issues). If you're strictly checking for an integer, then I suppose you're safe from SQL injection, XSS, etc., but you really need to have a handle on those issues, because sooner or later you're going to need to filter & validate something other than a simple integer.
you should always use the most efficient way to do it
if ( is_numeric($imput) && isset($input[3]) )
{
// your code
}
isset() is a language construct, which is always faster than strlen().
isset($input[n-1]) tells you whether string(data which passes through form is always string) has at least n long.
is_numeric() checks it is a valid num string.
i think it is better than ctype_digit() && strlen().

Alternative/faster methods of converting an integer to a cartesian coordinate?

As a fun side-project for myself to help in learning yet another PHP MVC framework, I've been writing Reversi / Othello as a PHP & Ajax application, mostly straightforward stuff. I decided against using a multidimensional array for a number of reasons and instead have a linear array ( in this case 64 elements long ) and a couple methods to convert from the coordinates to integers.
So I was curious, is there any other, possibly faster algorithms for converting an integer to a coordinate point?
function int2coord($i){
$x = (int)($i/8);
$y = $i - ($x*8);
return array($x, $y);
}
//Not a surprise but this is .003 MS slower on average
function int2coord_2($i){
$b = base_convert($i, 10, 8);
$x = (int) ($b != 0 ? $b/8 : 0); // could also be $b < 8 for condition
$y = $b % 10;
return array($x, $y);
}
And for posterity sake, the method I wrote for coord2int
function coord2int($x, $y){
return ($x*8)+$y;
}
Update:
So in the land of the weird, the results were not what I was expecting but using a pre-computed lookup table has predominantly shown to be the fastest, guess trading memory for speed is always a winner?
There was a table with times here but I cut it due to styling issues with SO.
Oh yes! This is a perfect example of binary:
function int2coord($i){
$x = $i >> 3;
$y = $i & 0x07;
return array($x, $y);
}
The reality is that a good compiler will find this optimization and use it, so it's not necessarily faster. Test and see if your compiler/interpreter does this.
It works because any binary division by 8 is the same as a right shift by 3 bits. Modern processors have barrel shifters that can do up to a 32 bit shift in one instruction.
The reverse is as easy:
function coord2int($x, $y){
return ($x << 3)+$y;
}
-Adam
I don't have the time to measure this myself right now, but I would suspect that a pre-computed lookup table would beat your solution in speed. The code would look something like this:
class Converter {
private $_table;
function __construct()
{
$this->_table = array();
for ($i=0; $i<64; $i++) {
$this->_table[$i] = array( (int)($i/8), (int)($i%8) );
}
}
function int2coord( $i )
{
return $this->_table[$i];
}
}
$conv = new Converter();
$coord = $conv->int2coord( 42 );
Of course, this does add a lot of over-head so in practice you would only bother to pre-compute all coordinates if you conversion code was called very often.
I'm not in a position to measure right now, but you should be able to eke out some additional speed with this:
function int2coord($i){
$y = $i%8;
$x = (int)($i/8);
return array($x, $y);
}
edit: ignore me -- Adam's bitshifting answer should be superior.
function int2coord_3($i){
return array((int) ($i / 8), ($i % 8));
}
this is a little faster because there is no var declaration and affectation.
I think most of your performance is lost by returning array(...) at the end. Instead, I propose:
* define two functions, one for x and one for y
or
* inline the bit arithmetic in code needing the calculation

Categories