This question already has answers here:
Determine Whether Two Date Ranges Overlap
(39 answers)
Closed 6 years ago.
I'm looking for a way to compare two lapses of time.
If the second lapse or part of it is in the first one -> return false.
Although, if the first one or a part of it is in the second one -> return false too.
I feel like I didn't have to skive math lessons...
I got
// first lapse
$a = strtotime('2016/05/04 22:50');
$b = strtotime('2016/05/20 22:15');
// second lapse
$y = strtotime('2016-05-12 12:00');
$z = strtotime('2016-05-20 10:00');
if (($y >= $a && $y <= $b) || ($z >= $a && $z <= $b)
|| ($a >= $y && $a <= $z) || ($b >= $y && $b <= $z))
return false;
But it's quiet confuse in my brain. I'm not sure it does what it supposes to do.
Thank you.
Edit
I found my question was duplicated with this one
if $a <= $b and $y <= $z, count
min($b, $z) - max($a, $y)
if < 0 - no overlap
= 0 - common boundary point
> 0 - overlap
Related
I'm trying to create a more simple version of if/else php statements because there are very many of them, so I want to make the code shorter and simpler.
I thought since each outputted value will equal a number going up from 0, then maybe I can do an array, but I'm also open to other solutions.
In human language, I want the value to be one of these numbers between 0 and 4 if it is within different parts of a range of numbers:
// 4 = 10,000+
// 3 = 1000-9,999
// 2 = 500-999
// 1 = 100-499
// 0 = <100
e.g. if $aa is 547, then $zz should equal the numeric value of 2, because it falls within 500-1000.
Now using if/else it's possible, and that works, but I want to make it shorter. Here it is in if/else statements:
if ( $aa >= 10000 ) {
$zz = 4;
} else if ( $aa >= 1000 && $aa < 10000 ) {
$zz = 3;
} else if ( $aa >= 500 && $aa < 1000 ) {
$zz = 2;
} else if ( $aa >= 100 && $aa < 500 ) {
$zz = 1;
} else {
$zz = 0;
}
Now I tried making an array but having trouble figuring out how to do this. Here's what I started with:
$b4 = $aa >= 10000;
$b3 = $aa >= 1000 && $aa < 10000;
$b2 = $aa >= 500 && $aa < 1000;
$b1 = $aa >= 100 && $aa < 500;
$b0 = $aa < 100;
$b_val = array( $b0, $b1, $b2, $b3, $b4 );
This is terribly wrong I know. It's not going to work like that, but maybe there's a way to make it work.
I thought of using switch, but it seems switch isn't designed for this, even though it can be done, and it isn't any shorter. I thought of using ternary, but that doesn't seem shorter either, unless you know how.
How to get a short, crisp, clean code to shorten the if/else statement on ranges of numbers?
You can use a nested ternary working smallest to largest
$zz = $aa < 100 ? 0 : ($aa < 500 ? 1 : ($aa < 1000 ? 2 : ($aa < 10000 ? 3 : 4)));
Demo ~ https://3v4l.org/MnqQv
I'd argue it's not as readable and therefore not as good as a plain old if..elseif..else or a function that returns at the appropriate logic branch.
function getRangeIndex($aa) {
if ($aa < 100) return 0;
if ($aa < 500) return 1;
if ($aa < 1000) return 2;
if ($aa < 10000) return 3;
return 4;
}
I have three integers: A, B, C
I want to print all integers from 1 to range which are divisible by A or B but not by C.
My code
for($n=0; $n < $range; $n++){
if(($n < $a && $n < $b) || ($n % $c == 0)){
return [];
}
if(($n % $a == 0 || $n % $b == 0) && ($n % $c > 0)){
$outputArr[] = $n;
}
}
Is there any more efficient way to do this?
You can speed this up but it is more complicated, especially if you must print these out in order. Here is a method that doesn't print them out in order.
First write a greatest common divisor (gcd) function in PHP, and then write a least common multiple (lcm) function that uses the gcd function. Compute m = lcm(a, b). Iterate over multiples of a and print them out if they are not divisible by c. Next, iterate over multiples of b and print them out if they are not divisible by m or c.
Other optimizations along these lines are possible. For example, you can precompute the multiples of a or b that are not multiples of m and store them in an array. This works if m is not too large, division is more expensive than array access in PHP, and range is significantly larger than m.
PHP version 7 or higher is so fast when only integer operations are used that micro-optimizations are no longer needed.
$res = [];
$a = 9;
$b = 13;
$c = 26;
$range = 10000;
for($n=$a; $n <= $range; $n += $a){
if($n%$c != 0) $res[] = $n;
}
for($n=$b; $n <= $range; $n += $b){
if($n%$c != 0) $res[] = $n;
}
$res = array_unique($res);
sort($res);
This example takes about 1 millisecond to calculate the 1411 values on my 8-year-old system. This time for the presentation of the result is several times greater.
I would use range() and array_filter().
$range = 20;
$A = 2;
$B = 3;
$C = 9;
$nums = array_filter(range(1, $range), function ($x) use ($A, $B, $C) {
return (!($x % $A) || !($x % $B)) && $x % $C;
});
var_dump($nums);
Here is a more optimized solution, that also works efficient when a and b are large. You can simply run through the multiples of a and b:
for($na=$a, $nb=$b; $na <= $range || $nb <= $range; ){
if ($na <= $nb) {
if ($na % $c != 0)
$outputArr[] = $na;
if ($na == $nb)
$nb += $b;
$na += $a;
} else {
if ($nb % $c != 0)
$outputArr[] = $nb;
$nb += $b;
}
}
Each output number is only generated once, and already in the desired order.
If you are afraid the modulo test is slow, you could also have a next multiple of c running along, but that looks like too much overhead.
I am currently teaching myself web development/ programming and to learn php i have built a simple program. The program takes user input and based on a series of math algorithms and calculates 7 random lottery numbers. The code is working fine but i want to improve it. The code is very repetitive and i want to simplify it by creating my own functions. I have created the first function that takes the users input, simply does some maths and then returns some values.
For Example...
<?php
function some_maths($int1 $int2 $int3){
$x = $int1 + $int2;
$y = $int2 * $int3;
$z = $y * $x;
return $x
....}
So this is pretty straight forward, but what i want to do now is take the values of X, Y, Z and create a function that checks to make sure they're not matching, or that they're not less than 1 or greater than 59. I used a while loop in my original code that goes like this:
while($x == $y || $x == $z || $x <1 || $x >59){
if( x> 59 || x < 1){
if (x<1){
do{ $x+=$int}while($x <1);
}elseif ($x > 59){
do{ $x-=$int}while($x >59);
}else $x++;
}
This seems to work fine but i don't want to have to repeat the same code over and over. I am sure there has to be a better way? Could i put the values into an array and maybe do it that way? What would be the best solution for this?
Your question is kind of vague but if I had to write a function to check if three numbers weren't equal and were < 59 and >1 this is how I would do it
function validateNumbers($x , $y , $z)
{
if(equal($x,$y)) return false;
if(equal($x,$z)) return false;
if(equal($y,$z)) return false;
if($x>59||$x<1) return false;
if($y>59||$y<1) return false;
if($z>59||$z<1) return false;
return true;
}
function equal($x , $y)
{
if($x == $y)return true;
else return fasle;
}
So far I only see two (pretty straightforward) things:
Your function prototype in the first example is missing commas between the parameters. Instead of function some_maths($int1 $int2 $int3) it should read function some_maths($int1, $int2, $int3).
In your second example a closing } is missing. But if I am interpreting your stuff correctly, the outer if-clause is redundant. Thus, the snippet can be simplified to:
Second example:
while($x == $y || $x == $z || $x <1 || $x >59){
if (x<1){
do{ $x+=$int}while($x <1);
}
elseif ($x > 59){
do{ $x-=$int}while($x >59);
}
else $x++;
}
There may be more room for improvement (e.g. slim down the condition of the outer while loop) - but for that we would need more context (what happens before your loop, what is $int, ...).
The first example:
$x = array("a" => 1, "b" => 2);
$y = array("b" => 1, "a" => 2);
$xLessY = ($x < $y);
$xGreaterY = ($x > $y);
var_dump($xLessY, $xGreaterY);
Result: $xLessY = true, $xGreaterY = true
The second example:
$x = array("a" => 2, "b" => 1);
$y = array("b" => 2, "a" => 1);
$xLessY = ($x < $y);
$xGreaterY = ($x > $y);
var_dump($xLessY, $xGreaterY);
Result: $xLessY = false, $xGreaterY = false
According to documentation on http://docs.php.net/manual/en/language.operators.comparison.php:
if key from operand 1 is not found in
operand 2 then arrays are
uncomparable, otherwise - compare
value by value
In our case each key from array $x is present in array $y, so $x and $y are comparable.
See also the example from documentation:
// Arrays are compared like this with standard comparison operators
function standard_array_compare($op1, $op2)
{
if (count($op1) < count($op2)) {
return -1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return 1; // $op1 > $op2
}
foreach ($op1 as $key => $val) {
if (!array_key_exists($key, $op2)) {
return null; // uncomparable
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
This behaviour is really strange: $x is less than $y and at the same time $x is greater than $y (the first example) and two arrays are comparable.
I think this is because php always compares starting from the one definite side of sign '<'. I mean: for ($x < $y) php takes $x as operand 1, for ($x > $y) it takes $y as operand 1. Although I didn't find anything about this behaviour in documentation.
What are your thoughts on this?
Your assumption is correct. The > operator is parsed as
| expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); }
This basically says, X > Y is equivalent to not X < Y, which is of course wrong when the comparison is not commutative. Consider reporting this on bugs.php.net.
I wouldn't say the bug is in $x > $y being substituted for $y < $x.
Sure, if you implemented $x > $y in a way that the arguments did not exchange positions when passed to the comparison function, you would solve this particular problem. But you get another in return.
Right now you have:
$x < $y <=> cmp($x, $y) == -1
$x > $y <=> cmp($y, $x) == -1
Because the first key of the first argument is always compared first, both conditions are true if reset($x) < $y[key($x)] and reset($y) < $x[key($y)].
But consider another implementation, which would solve this problem:
$x < $y <=> cmp($x, $y) == -1
$x > $y <=> cmp($x, $y) == +1
Now < and > are consistent when the order of the operands is fixed, but we now get weird behavior when we swap the operands because we could still have cmp($x, $y) == -1 and cmp($y, $x) == -1, which would mean $x < $y and $y < $x would both be true.
In sum, the only solution would be to fix the comparison function so that its behavior was antisymmetric, i.e. so that cmp($x, $y) == - cmp($y, $x), at least within a set of elements that are claimed to be comparable.
I may be wrong but I don't think you can compare arrays that way. I always assumed one can check for equality or inequality, but not compare quantities with < and >.
The man page on array operators seems to confirm this.
Can I use if(4 <= $a <= 44) instead of if(4 <= $a && $a <= 44)?
No, you can't do that.
if(4 <= $a <= 44) is equivalent to if((4 <= $a) <= 44). This may be equivalent to if(false <= 44) or if(true <= 44), neither of which makes sense.
No, you can't.
if(4 <= $a <= 44) will (I believe) be parsed as if ((4 <= $a) <= 44), which checks whether (4 <= $a) (which is either 0 or 1) is less than 44.
No, you can't (as all others already said).
Comparison operators in PHP, as their name implies, allow you to compare two values, and with the expression
4 <= $a <= 44
you would be comparing three values. Read here for a complete explanation.