Identity the available range numbers when two range numbers are overlap - php

If I have an existing range:
1-10
11-50
Then I will enter a new range from 1 - 60, How could I detect that the new range to be added overlaps to the previous entries? And how can I get the available range? In this case the available range is from 51-60.
Does anyone here have a great idea on this?
Thanks for helping.
Here's my current code:
$saved = array(
array(
"start" => 1,
"end" => 10
),
array(
"start" => 10,
"end" => 50
)
);
$new_range = array(
"start" => 1,
"end" => 60
);
$usable_range = array();
$previous_from = 0;
$previous_to = 0;
foreach($saved as $value)
{
$range_start = 0;
$range_end = 0;
if($previous_from<$value['start'])
{
$previous_from = $value['start'];
}
if($previous_to<$value['end'])
{
$previous_to = $value['end'];
}
if($previous_from<=$new_range['start'])
{
if($previous_to<$new_range['end'])
{
$range_start = $previous_to+1;
$range_end = $new_range['end'];
$new_range['start'] = $range_start;
}
}
else if($previous_from>=$new_range['start'])
{
if($previous_to<$new_range['end'])
{
$range_start = $previous_to+1;
$range_end = $new_range['end'];
$new_range['start'] = $range_start;
}
}
$usable[] = array("range_start"=>$range_start,"range_end"=>$range_end);
}

Call every interval (min,max)
1) Sort your list of intervals by their min.
2) Check to see if any max is greater than the next entry over's min. If they are, create the interval that is the smaller of their mins and the greater of their maxes, and add it back into the list in place of those two.
3) Whenever you get a new interval, binary search into the list to add it, sorted by min. Then, using similar logic as in 2), attempt to merge it with the entry one below and one above until no more merges are possible.
EDIT: A few changes.
First, since we're using integers not floats, if you have an interval like 1,10 and 11,20 then there is no 'gap' between the 10 and 11 - so we should consider this to be one larger interval, 1,20. Reflect this by, instead of checking to see if max > next min, if max >= next min - 1.
Second, if you want to find all intervals formed by overlap when merging a new interval into your list of intervals:
1) Since your list of intervals is known to be in a state where it is sorted by min and also sorted by max, binary search into it to find the lowest min just above your new min and the highest max just above your new max.
2) Iterate over min, max, min, max... etc in your array that are between your new min and new max. Below the lowest min, above the highest max and between each max/min you can compute the interval that is in the 'gap' there, and return them in e.g. an array.
For example if your list of intervals contains 13,16, 21,24 and 31, 38 and you want to calculate the non-overlap of the new interval 1,30:
1) We binary search into our list and find that 13 is the lowest min above 1 and 24 is the highest max above 30.
2) We iterate like so:
Between our min and the lowest min is 1 and 13 - so this forms an interval 1,12 (inclusive bottom, exclusive top). Add onto the return array.
Between max and the next min is 16 and 21 - so this forms an interval 17,20 (exclusive on both ends). Add onto the return array.
Between max and our max is 24 and 30 - so this forms an interval 25,30 (exclusive bottom, inclusive top). Add onto the return array.

Finding overlap can be described as finding an intersection. Likewise finding the available range can be described as finding the difference. One way of doing this would be treating these sets as arrays and using the array_intersect [1] and array_diff [2] functions.
That is all I can come up with given your details.
[1] - http://php.net/manual/en/function.array-intersect.php
[2] - http://www.php.net/manual/en/function.array-diff.php

Related

Calculate soccer matches combinations without repetition

So, I have an array like this, filled with teams:
array(0, 1, 2, 3, 4, 5, ...)
At every tournament, we have TotalNumberOfTeams-1 rounds (dates) with matches. (1st loop)
At every round, we have TotalNumberOfTeams/2 matches. (2 loop)
How is possible to calculate the combinations for this result:
Date Date Date Date Date
Match: 0-1 0-2 0-3 0-4 0-5
Match: 2-3 1-5 1-4 1-3 1-2
Match: 4-5 3-4 2-5 2-4 3-5
/w common words: Every team plays every round with different team
Code to calculate rounds, matches and dates:
// Rounds
for($i=1; $i <= ($teamsNum - 1); $i++) {
// Matches
for($z=0; $z < ($teamsNum / 2); $z++){
//some code here
}
// Calculate next date
$mdate = date('Y-m-d', strtotime($mdate. ' + x days'));
}
Use round-robin tournament algorithm.
In short:
Make two rows of commands, every top command plays with corresponding command form lower row. I number is odd, one command rests.
Shift all command except for the first in circular manner
0 1
2 3
=====
0 2
3 1
====
0 3
1 2
there is an answer with code example - http://rosettacode.org/wiki/Combinations#php
just use $k=2 for yours calculations

Find all combinations of x numbers where they sum to Y

I'm trying to write this solution in PHP.
Inputs:
number of numbers = x
smallest number = 1
sum of numbers = y
I'm not dealing with very large numbers, largest x is approximatly 50, largest y is approximatly 80.
rules: Within each set of numbers, the number proceeding the previous must be equal to or greater.
For example
x = 3
min = 1
y = 6
solution:
(1,1,4),(1,2,3)
note that (3,2,1) isn't a solution as they are in descending order.
This is easily solved via recursion. The time complexity though will be high. For a better (but slightly more complex solution) use dynamic programming.
Here's the idea:
If the size of the set is 1 then the only possible solution is the desired sum.
If the set is larger than one then you can merge a number X between the minimum and the desired sum with a set of numbers which add up to the desired sum minus X.
function tuplesThatSumUpTo($desiredSum, $minimumNumber, $setSize) {
$tuples = [];
if ($setSize <= 1) {
return [ [ $desiredSum ] ]; //A set of sets of size 1 e.g. a set of the desired sum
}
for ($i = $minimumNumber;$i < $desiredSum;$i++) {
$partial = tuplesThatSumUpTo($desiredSum-$i, $minimumNumber,$setSize-1);
$tuples = array_merge($tuples, array_map(function ($tuple) use ($i) {
$res = array_merge([$i], $tuple);
sort($res);
return $res;
},$partial));
}
return array_unique($tuples,SORT_REGULAR);
}
See it run:
http://sandbox.onlinephpfunctions.com/code/1b0e507f8c2fcf06f4598005bf87ee98ad2505b3
The dynamic programming approach would have you instead hold an array of sets with partial sums and refer back to it to fill in what you need later on.

Php Division remainders & Arrays

I have an array
$blocks
It has 4 items with constant values
A, B, C, D
$blocks["a"] = 20;
$blocks["b"] = 1000;
$blocks["c"] = 10000;
$blocks["d"] = 50000;
Another function returns a value, lets say 358020
(It's usually high but can drop to a few tens
How would I write a function that will take this value and return an array of how many of each item exists.
Example output something like:
$output["a"] = 1;
$output["b"] = 3;
$output["c"] = 0;
$output["d"] = 7;
Starting with the largest block, how many of that block fits into the value, then the remainder is passed to the next largest, and so on...
calculateNumberCredits(25000);
function calculateNumberCredits($experience) {
# The credits we have
$credits = array(
'a' => '10000',
'b' => '2000',
'c' => '1000',
);
# Keep track of the amount needed per credit
$timesCreditNeeded = array();
# Start calculating the amount per credit we need
foreach($credits as $creditID => $creditAmount) {
# 1) Calculate the number of times the amount fits within the amount of experience
$times = floor($experience / $creditAmount);
# 2) Calculate the remainder of the above division en cache is for the next calculation
$experience = $experience % $creditAmount;
# 3) Cache the number of times the credit fits within the experience
$timesCreditNeeded[$creditID] = $times;
}
echo '<pre>';
print_r($timesCreditNeeded);
return $timesCreditNeeded;
}
// Will return Array ( [a] => 2 [b] => 2 [c] => 1 )
I loop through the credits you have in your system. In this example the credits are order from high to low. When this is not the case you should order them te get the desired result.
1) For each credit i try to find the max number of times the credit fits within the experience of the particular user. Because floatnumber make no sense we floor() the result of the division.
2) After i found the number of times the credit fits, I calculate the remainder for the next iteration (next credit). You can find the remainder by calculating the modulus.
3) Last but not least I cache the number of times the credit fits.
Hope this helps!

User defined number ranges

I have a function where for a specific number range a percentage has to be applied:
0-100 EUR: 5%
>100 EUR: 3%
This number ranges and percentages should be user-defined.
The implementation should be as simple as possible.
What would you suggest for specifying the ranges and calculating the result?
Assuming you have access to some kind of database, I'd store the values there. You would need 3 tables at minimum:
ranges
id_range
from_number
until_number
percentage
users
id_user
user-ranges
id_range
id_user
Make the from_number and until_number columns nullable, to represent anything up to X and anything after Y.
Here's my short approach for calculating the result with defined rules in an array
$rules = array(
5 => '0-100 EUR', // here the percentages and their corresponding values
3 => '> 100 EUR'
);
$rand = mt_rand(0, 100); // calculate a random percent value
$lastPercentage = 0;
foreach($rules as $percentage => $val) {
// create a range from 0-5 (in the first iteration)
// every next iteration it is lastPercentage + 1 (5 + 1 in this case) to lastPercentage + current percentage
$range = range($lastPercentage, $percentage + $lastPercentage);
// yep, it is in the percentage range
if (in_array($rand, $range)) {
echo $lastPercentage,' < '.$rand.' > '.($percentage + $lastPercentage);
}
$lastPercentage = $percentage + 1; // +1 so that there are no overlapping ranges
}

How do I find the ceiling and floor for a number from a set of numbers?

1st number: 50
2. 30
3. 70
4. 40
5. 11
and other number is 33
I need to calculate which two numbers the last number is between (using php) .. any help?
Iterate over your list and find the following two values:
The largest number that is smaller than your target number.
The smallest number that is larger than your target number.
In pseudo-code:
lowerlimit = Unknown
upperlimit = Unknown
for each n in list:
if (n <= target) and (lowerlimit is Unknown or n > lowerlimit):
lowerlimit = n
if (n >= target) and (upperlimit is Unknown or n < upperlimit):
upperlimit = n
Then lowerlimit and upperlimit are your answer. This algorithm requires O(n) time and O(1) extra space.
If you are going to test the same list with many different target numbers then it could make sense to sort the list first requiring O(n log(n)) time, but then you can find the limits in just O(log(n)) time using a binary search.
I'll not give you the code but give you some guidelines for your homework.
You need to do these steps to solve your problem.
Sort your list of numbers. (I guess you are storing them in an array so sort the array.)
With a for loop search for the place where the element N is bigger than your number and the element N-1 is smaller. That will give you your position.
Oh and to avoid really long loop. use "break" after you find your position.
Sorted List:
11
30
// your 33 is bigger than 30 and smaller than 40, so this is the position you want.
40
50
70
function isBetween($several_numbers, $number)
{
$return_numbers = array();
sort($several_numbers);
$j = 0;
//find the first number in the array that $number is bigger than
while($number > $several_numbers[$j]) $j++;
if ($j == 0 || $j > count($several_numbers) - 1) return array();
$return_numbers[0] = $several_numbers[$j-1];
while($number > $several_numbers[$j]) $j++;
if ($j > count($several_numbers)-1) return array();
$return_numbers[1] = $several_numbers[$j];
return $return_numbers;
}
print_r(isBetween(array(50, 30, 70, 40, 10), 33));
I don't know if I understood correctly but this seems to be it

Categories