I've created a question and answer page to determine the level of interest of each user for different products
like this:
how much u like x (betwin 1-10)
These questions are more than 30, and if I want to write a single command line for each possibilities, it's almost impossible.
the commands do like this:
if $a <=5 and $b <=6 and $c <=7 and... do ...
if $a<= 8 and $b <=7 and $c >= 5 and $d <=8 do...
I want the commands to work this way
Is there a better way to do this?
thanks
For this you could use a switch statement. Documentation: http://php.net/manual/en/control-structures.switch.php
Example code:
$i = 10;
switch($i):
case ($i <= 0): // or for example: case (0)
return 'It\'s 0 or lower than 0';
break;
case ($i > 0 && $i < 10):
return 'Number is between 0 and 10';
break;
case ($i >= 10):
return 'Number is 10 or higher';
break;
default:
return false;
endswitch;
// You can use echo instead of return, but i prefer to use these statements in a function instead of the html page.
More information about the differences between if and switch is provided by Masivuye Cokile as a comment in your question: Which is Faster and better, Switch Case or if else if?
I hope this helped. Let me know.
Related
Is there a way to optimize something like this?
I have already tried and it doesn't work (at least in php)
$foo = 6;
if ($foo != (3 or 5 or 10)) echo "it work";
elseif($foo < (5 or 10)) echo "it work again";
else echo "it doesn't work;"
I want to know if there's a better way to write that kind of validations.
But if something like this work in other langs, please let me know.
EDIT:
answer for this
($foo != (3 or 5 or 10)) -> in_array($foo,array(3,5,10))
does the same work if i want something like
($foo != (3 and 5 and 10))
No. It's not. You're testing your $foo value against the BOOLEAN result of those or operations. It'll boil down to
if ($foo != (true or true or true))
which is simply
if ($foo != true)
if (!$foo)
If you want to test a single value against multiple values, you can try
if(!in_array($foo, array(3,5,10))) { ... }
instead. For your < version, this won't work. You'll have to test each value individually:
if (($foo < 5) or ($foo < 10)) { ... }
though technically this is somewhat redundant, since if $foo is less than 5, it's already less than 10.
For the first you can use
if(!in_array($foo, [5,10,15]))
The second thing doesn't work in any language cause less then 5 or 10 is true for every thing less than 10. So no need for the 5. But I get your point. I don't know a fast way doing this
In python you can do this:
if(5 < x < 10)
a, b = b, a // swapping these two
I agree with the other answers and also, if you have more processing to do, you could also do something like this:
<?php
$x = 3;
switch ($x)
{
case 6:
$x = 5;
case 3:
case 7:
$x = 5;
case 5:
echo 'It is working' . PHP_EOL;
break;
}
EDIT: Thanks DanFromGermany for pointing the stacked cases. Added them as an example.
NOTE: I am aware that this is not acceptable code, I am seeking to understand what the interpreter is doing, not advice on how else to achieve the same result!
I've since read up enough to realize that I can't and shouldn't be attempting to use |,|| or XOR in defining a switch caseāso please don't comment to the effect of "don't do that", I'm just trying to understand what the interpreter is doing with such statements and to understand the strangeness of the behavior. I'm using PHP 5.3.1.
This is what I was actually intending to do and am now using, please don't recommend code:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : -5; //angle from goal
break;
case 1:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
case 2:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -10; //miss penalty
break;
case 3:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : -10; //error penalty
break;
}
}
But got curious if I could do:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0 || 1:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15; //angle from goal
break;
case 2 || 3:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
}
}
and, perversely, this does run, but very slowly (like, seconds), and though of course it evaluates (0||1) not at all the way I'd intended (and indeed today was a lesson on the difference between bitwise and logical operators).
But more curious to me was the fact that I could do this, if very slowly and not with the results I'd wanted:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0 XOR 1:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15; //angle from goal
break;
case 2:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
case 3:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
}
}
But I could not do this:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0 XOR 1:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15; //angle from goal
break;
case 2 XOR 3:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
}
}
This was the only one of these terrible, terrible ideas that PHP wouldn't even evaluate.
My question is: why does evaluating these statements take so, so much longer, and why does the last example not run? I considered that PHP was interpreting 0 XOR 1 and comparing true and false, but I couldn't substitute those in and have it still evaluate. Anyone know what's happening here? Thanks!
UPDATE:
Comments requested a var_dump($this->header) (in case it isn't obvious, I truncated my initial switch statement from 7 cases to 4 just to avoid spamming lines of identical code, but, given that the var_dump() was requested, I chose to post the whole thing in case it revealed something I couldn't forsee!). Also, yes, it turns out I'd been using an associative array due to forgetting to have called array_values() before setting $this->header, in the second answer below, having made this error turns out to explain the duration of the switch statement, whilst the first answer and second answer together are great walkthroughs of the logic.
array(12) {
["theZone"]=>
NULL
["leftMiss"]=>
NULL
["rightMiss"]=>
NULL
["leftError"]=>
NULL
["rightError"]=>
NULL
["leftHit"]=>
NULL
["rightHit"]=>
NULL
["accuracy"]=>
string(5) "false"
["rt"]=>
string(4) "true"
["disease"]=>
string(3) "yes"
["bars"]=>
string(3) "yes"
["endMessage"]=>
NULL
}
case values have to be SINGLE values. You can't do 2 || 3, because that'll evaluate as
case (2 or 3) -> case TRUE
Similarly, if you were using && (and), you'd get
case (0 and 1) -> case FALSE
You can use 'fallthrough' behavior for the OR logic:
case 2:
case 3:
...code here ...
break;
XOR, you can't do. not with a simple case statement.
comment followup:
for ($i = 0; $i < 5; $i++) {
switch($i) {
case 0 xor 1: echo "0 xor 1: $i\n"; break;
case 2 xor 3: echo "2 xor 3: $i\n"; break;
}
}
will output
2x3: 0
0x1: 1
0x1: 2
0x1: 3
0x1: 4
and
php > var_dump(2 xor 3);
bool(false)
php > var_dump(0 xor 1);
bool(true)
Remember that switch cases evaluate the same ==. They're lazy comparisons, not checking types. So your 2 xor 3 is evaluated the same as if the case has been case false, which makes the $i=0 condition match.
Haha, it's quite funny, what you did there.
It's not the switch which gets you into performance troubles. It probably is your for-loop in combination with your switch.
I try to explain it with the second example given.
However, I just have to guess, and so I have to assume that your $this->header array looks like the following (this would be the only reason for your performance leak):
$this->header = array(
999 => 10, // the value is irrelevant, only the key (2) matters
998 => 15
);
Now lets play interpreter debugger.
set $i to 0
is $i<count($this->header)? yes, because header size is 2
is ($i == (0 || 1))? no, because (0 == (0 || 1)) equals (0 == true) equals (false == true) can never be true
is ($i == (2 || 3))? no, because (0 == (2 || 3)) equals (0 == true) equals (false == true) will never comply
next loop, increment $i (set $i to 1)
is ($i<count($this->header)? yes, because header size is 2
is ($i == (0 || 1))? yes, because (1 == (0 || 1)) equals (1 == true) equals (true == true)
go into case statement
set $this->header[1] to -5 (remember the index 1 does not exist so far in your array)
next loop, increment $i (set $i to 2)
is $i<count($this->header)? yes, because header size is 3 (remember? you just added a new index which incremented your header size)
is ($i == (0 || 1))? yes, because (2 == (0 || 1)) equals (2 == true equals (true == true)
go into case statement
set $this->header[2] to -5 (again index 2 did not exist so far)
next loop, increment $i (set $i to 3)
is $i<count($this->header)? yes, because header size is 4 (again, you just added a new index)
Now this will continue until the header size equals $i. In the example above this would happen after 998 iterations, because this would be the first time when there won't be a new index creation (the existing one - 998 - would simply be used), resulting in count($this->header) not changing.
In your first example, this will not happen. The header size will stop to change after the fourth iteration, because the case statement tries to compare integer values instead of booleans. As soon as it reaches index 5 it tries to compare to the values 1, 2, 3 and 4 and will not match a single one, resulting in no new index creation.
To fix the the performance issue, you should make sure that every key in your array exists and also change your for-loop as follows:
$size = count($this->header);
for($i=0; $i<$size); $i++) {...}
Of course this won't fix your logical problems. But since you asked for what is going on, this should be a good explanation, I guess.
var_dump()-ing your $this->header array before and after your loop should prove me right :)
===
Sorry for deleting and undeleting this answer. Just wanted to make sure it really behaves as explained. If you could provide me with a var_dump of your header array, it would be great.
I'm creating through a PHP loop (the reason of the loop is because I want more or less cases) a switch Javascript function, that outputs this:
function my_function(array_name) {
switch (true) {
case (array_name[1] < x < array_name[2]):
console.log("between: 1 & 2");
break;
case (array_name[2] < x < array_name[3]):
console.log("between: 2 & 3");
break;
default:
console.log("none");
break;
}
}
Now when the document is loaded I create a Javascript array which contains the values I want to pass to the function.
var array_to_execute = [0,1000,2000,3000];
How can I call the function after this array is created passing these values? Something like:
my_function(array_to_execute);
That would result in executing:
switch (true) {
case (1000 < x < 2000):
console.log("between: 1 & 2");
break;
case (2000 < x < 3000):
console.log("between: 2 & 3");
break;
default:
console.log("none");
break;
}
The function call that you've got in mind (my_function(array_to_execute)) should be just fine!
The problems you're probably having are because:
case (array_name[1] < x < array_name[2]):
does not work the way you think it does. (It ends up comparing a truth value to a number.) Use this instead and you should be good to go:
case (array_name[1] < x && x < array_name[2]):
I am trying to say $level > -100 && $level < 100
$level = 0;
switch($level){
case $level > -100:
break;
case $level < 100:
break;
default:
echo '5';
return null;
}
can you use a switch statement like this.
None of the answers presented so far have explicitly connected the spirit of the original question with a proper switch construction. So, for the record:
switch (true) {
case (($level>-100) && ($level<100)):
echo 'in range one';
break;
case (($level>200) && ($level<300)):
echo 'in range two';
break;
default:
echo 'out of range';
}
There's absolutely nothing wrong with this usage of switch.
When you say switch ($level) you're already comparing the value of $level. Each case can then only check for equality, you can't do comparisons like in your example. You'll have to use an if statement instead:
if ($level > -100 && $level < 100)
; // do nothing; equivalent of break in this case
else
echo '5';
Even simpler, just negate the conditions:
if ($level <= -100 || $level >= 100)
echo '5';
Apart of if/else, another way to do it:
switch (true)
case $level > -100:
break;
case $level < 100:
break;
default:
echo '5';
return null;
}
The other answers are both correct and incorrect at the same time. Incorrect, in that it is possible to do what you want in PHP... change switch($level) to switch(true) and your example will work. Correct, in that it's bad form and if any other programmers see that in your code they'll probably come after you with pitchforks. Its not how the switch statement is intended to be used, and wouldn't work like that in most other languages.
No you can't. Switch does only 'equals' type comparison.
No, you can't. The switch statement needs literals in the case blocks. Use an if statements instead:
if(!($level > -100 && $level < 100))
{
echo '5';
return null;
}
This is one of the reasons people advocating case as a superior solution to if-else are off base. I don't like the syntax or the limitations - if-ifelse-else is much more useful.
I don't understand what's happening here. Logically, it doesn't make any sense to me.
<?php
$level = 0;
switch ($level) {
case $level > 80: $answer = 'high'; break;
case $level > 60: $answer = 'moderate-to-high'; break;
case $level > 40: $answer = 'moderate'; break;
case $level > 20: $answer = 'low-to-moderate'; break;
default: $answer = 'low'; break;
}
echo $answer;
?>
When $level == 0, it returns "high". This doesn't make any sense to me. Can someone explain what's happening here?
Change switch ($level) to switch (true) and this will work.
switch statements perform equality tests on the values in the cases. PHP is evaluating your > comparisons, so case $level > 80 becomes case false. false is considered to be equal to 0, so the first case matches.
The quantity after the case needs to be just the value, not a boolean expression. I'm guessing that PHP is evaluating case $level > 80 as case ($level > 80) which is becoming case 0 (i.e., false, since $level is indeed NOT less than 80) and so you're matching the first case.
Are you sure you can do this in php?
I just checked the manual of switch and you have to provide a distinct value.
I think if you can write it again into something like:
$levelDivTwenty = intval($level/20);
$levelDivTwenty = ($levelDivTwenty>4)?4:$levelDivTwenty;
and then case on that.
switch ($levelDivTwenty) {
case 4: //same as $level > 80 before...
case 3: //>60 etc...
}
As others have pointed out you can't use switch like that, but how about defining it like this:
<?
$level = 21;
$answers = array('low', 'low-to-moderate',
'moderate', 'moderate-to-high', 'high');
echo $answers[intval(($level-1)/20)];
?>
Note: If $level = 0, then expression inside intval() will be -1/20, which is less then -1 and therefore will be rounded to 0.
This isn't really how switch is intended to be used. It's to evaluate for a specific value.
Use an If/else if here, instead of complicating your life to make a switch work like one.