Best way to get N numbers from range betwen 2 (big) numbers - php

Hello I need to get N numbers from range between 2 big numbers, without the start and end numbers.
The (N) numbers must be on equal intervals... I will try to explain with small numbers:
<?php
$rangeStart = 0;
$rangeEnd = 100;
$n = 9;
In this example i need to get 10,20,30,40,50,60,70,80,90
I have try with 'for loop' but it is veeery slow, because I'm using range like 1207083600 ~ 1275512399
Will appreciate any help.
=====
This is what I call slow http://jsfiddle.net/pbF7N/1/
The start and end are timestamps and I need to extract 10 dates...

range() with its optional 3rd parameter to specify the step size...
range(10, 90, 10);
$range = range(10, 90, 10);
print_r($range);
Array
(
[0] => 10
[1] => 20
[2] => 30
[3] => 40
[4] => 50
[5] => 60
[6] => 70
[7] => 80
[8] => 90
)

Something like this maybe:
function nrange($num, $start, $end)
{
$out = array(); $i = 0;
$interval = floor(($end - $start) / ($num + 1));
while ($i++ < $num )
$out[] = $start + $i * $interval;
return $out;
}

Consider first your example case. Your numbers broke up the range [0..100) into 10 equal intervals, [0..10), [10, 20), etc. up to [90..100).
Notice that the number of intervals is $n+1. So you see that each interval is of length ($rangeEnd - $rangeStart) / $n.
Using this information, you can use range to step across $interval numbers at a time, i.e.,
$interval = ($rangeEnd - $rangeStart) / $n;
$range = range($rangeStart, $rangeEnd, $interval);

Related

How to count days of year PHP to create day range array wrapping past day 365 to day 1

I have a database table with content for each day of the year and I'm trying to return the current day and the next 9 days to my PHP app.
Day 1 = Lorem ipsum
Day 2 = Lorem ipsum
Day 3 = Lorem ipsum
Day 365 = Lorem ipsum
I have a basic function that gets the current day of year in PHP and creates an array of the subsequent 10 days:
$today = date(z);
$subsequent_days = 9;
$days_arr = range($today, $today+$subsequent_days);
Example: If today is 12/27, the day number is 360, the resulting array is (360, 361, 362, 363, 364, 365, 366, 367, 368, 369)
The problem I'm trying to solve is that when I feed that array into my database query to get the current and upcoming 9 days, if the current date is less than 10 days from the end of the year (as in the example above) then it only returns me that many days back.
What I'm looking for is a simple/clean way to have the days_arr stop at 365 and restart at 1 to complete the 10 values in the returned array.
So the end result I'm looking for is: (360, 361, 362, 363, 364, 365, 1, 2, 3, 4)
You can just use the modular operator:
<?php
$ten_days = function($from) {
for(
$range = [], $i = 0;
$i<10;
$range[] = ($from + $i) % 365, $i++
);
return $range;
};
var_export($ten_days(360));
Output:
array (
0 => 360,
1 => 361,
2 => 362,
3 => 363,
4 => 364,
5 => 0,
6 => 1,
7 => 2,
8 => 3,
9 => 4,
)
Note: This is assuming a year of 365 days, 0 indexed. You will have to adjust for leap years.
You can adjust the for loop above for 1 indexed days:
for(
$range = [], $i = -1;
$i<9;
$range[] = ($from + $i) % 365 + 1, $i++
);
A simple solution can be achieved using modulo % operator. Using range() is convenient, but doesn't give you the flexibility of using modulo. Not sure if you need to account for leap years, so adding it as an arg:
<?php
$day_seq = function($start, $isleap) {
// Convert human's 1-indexed day to zero-indexed day
$start--;
$numdays = $isleap ? 366 : 365;
// Build 10-day sequence, adding 1 to re-calibrate to human's 1-indexed counting
for($seq = [], $i = 0; $i<10; $i++) {
$seq[] = (($start + $i) % $numdays) + 1;
}
return $seq;
};
print_r($day_seq(360,0));
Output:
Array
(
[0] => 360
[1] => 361
[2] => 362
[3] => 363
[4] => 364
[5] => 365
[6] => 1
[7] => 2
[8] => 3
[9] => 4
)

PHP: Seperate a number to 10er array with a minimum and maximum value

I do not know how to form this the right way so here is the concept.
I have for example the 93.5 and 35 as numbers.
What i would like to do is to get from the minimum value the previous 10er number, in this case the 30 and get from the maximum value the next 10er number which in this case is 100.
The next step is to get an array from each 10er number between those two numbers. It would look like this:
array(8 items)
0 => 30
1 => 40
2 => 50
3 => 60
4 => 70
5 => 80
6 => 90
7 => 100
So the question is, how do i achieve that with PHP
After some coding i have found the solution.
First step: Get the minimum and maximum numbers and set them to the previous and next 10er number:
$minSize = floor(35 / 10) * 10; /* Gives back 30 */
$maxSize = ceil( 93.5 / 10) * 10; /* Gives back 100*/
Now get the number from the $maxSize didvided by 10.
$devidedNumber = $maxSize / 10; /* Gives back 10 */
After that, a for iteration is to be created using the $devidedNumber in order to decide how many times this iteration should run.
$sizedArray = array();
for ($i = $minSize/10; $i <= $devidedNumber; $i++)
{
$sizedArray[] = $i * 10;
}
The $i starts from 3 because we need the value that starts from 30 to the target value.
And the result:
array(8 items)
0 => 30
1 => 40
2 => 50
3 => 60
4 => 70
5 => 80
6 => 90
7 => 100
EDIT:
After #Nigel Ren answer, another way to do it is the following. After rounding the numbers, the for iteration could look like this:
for ($i = $minSize; $i <= $maxSize; $i+=10)
{
$sizedArray[] = $l;
}
In this case, the code is simplified by removing the line
$devidedNumber = $maxSize / 10; /* Gives back 10 */
and get directly the between values from the rounded.
Thanks for the nice suggestion

Round up numbers

I get some numbers from database. I would like round up these numbers this way:
Database => Round up number
34 => 0
89 => 100
421 => 400
561 => 600
4421 => 4000
6701 => 7000
45000 => 50000
91000 => 90000
132000 => 130000
Is there any php function to do this? So numbers under 1000 would be round up closest full 100. Over thousands would be rounded up to nearest full 1000 figure. And if number is over 10 000 then it would be always rounded up to closest full 10 000.
Hopefully you understand what I'm after.
Since I'm fed up of people not reading the damn question...
function myRound(int $number) : int {
// remove typehints if you're on old versions of PHP...
$magnitude = abs($number);
if( $magnitude < 1000) $precision = -2;
elseif( $magnitude < 10000) $precision = -3;
else $precision = -4;
return round($number,$precision);
}
IDEOne test
You can use some simple math(mostly to calc num length) and build in with negative precision round() function
function customRound($number) {
return round($number, -floor(log10($number)));
}
echo customRound(6701); // sample of usage
-floor(log10($number)) this part is to calc length of num - 1 and also it is negated for round() needs
Have a look at the round() function here
http://php.net/manual/en/function.round.php
and the ceil() function here
http://php.net/manual/en/function.ceil.php
Something like
$number = 1;
$number = ceil($number / 10) * 10;
echo $number;
Here is one solution:
$numbers = [
34,
89,
421,
561,
4421,
6701,
45000,
91000,
132000
];
foreach ($numbers as $number) {
$len = strlen((string)$number);
$precision = $len - 1;
$precision = $len <= 2 ? 2 : $precision;
$precision = $len > 4 ? 4 : $precision;
echo $number . ' => '. round($number, -1 * $precision) . PHP_EOL;
}
Outputs:
34 => 0
89 => 100
421 => 400
561 => 600
4421 => 4000
6701 => 7000
45000 => 50000
91000 => 90000
132000 => 130000
You can use a function like this:
$number = 45000;
function rounder($num)
{
$length = strlen($num);
if(is_int($num))
{
if($num < 100)
return round($num, -($length));
elseif($num < 1000 || $num <= 9999)
return round($num, -($length-1));
else
return round($num, -4);
}
}
echo rounder($number);
Though not tested, should work..

Alternating Algorithm Starting from Center

I'm trying to figure out an algorithm to come up with an arrayed result that are equidistant alternating points from the center (can be percent based). So, my end result would be something like:
X = 20 (separation distance based on # of items) - 100 / 5 (5 items spread out over 100%)
A = 50 (center point)
B = 70 (A + 20)
C = 30 (A - 20)
D = 90 (B + 20)
E = 10 (C - 20)
Another result would be if we have 10 items (X = 100 / 10):
A = 50 (center point)
B = 60 (A + 10)
C = 40 (A - 10)
D = 70 (B + 10)
E = 30 (C - 10)
F = 80 (D + 10)
G = 20 (E - 10)
H = 90 (F + 10)
I = 10 (G - 10)
J = 100 (H + 10)
If it's important, I'm trying to arrive at this algorithm using PHP. I'm not much of a Math wiz so I'm not sure if there's a name for this type of calculation. Thanks!
You could write a function like:
function getArrayEquidistant($startValue, $step, $nbEntries)
{
$i = 0;
$count = 1;
$final = array();
$final[] = $startValue;
while($i < $nbEntries)
{
if ($i % 2 == 0)
$final[] = $startValue + ($count * $step);
else
{
$final[] = $startValue + ($count * $step);
$count++;
}
$i++;
}
retun $final;
}
Where $startValue is the initial value (at index 0), $step is the value added or sub at each iteration, and $nbEntries the number of entries after the initial value.
As example:
print_r(getArrayEquidistant(50, 20, 10));
will give you:
Array
(
[0] => 50
[1] => 70
[2] => 30
[3] => 90
[4] => 10
[5] => 110
[6] => -10
[7] => 130
[8] => -30
[9] => 150
[10] => -50
)
If I understood you correctly, this should work:
function pointsArray($center, $numPoints) {
$arr = array();
$arr[0] = $center;
for($i = 1;$i < $numPoints; $i++)
$arr[$i] = $i%2 == 0 ? $center - ($i-1)*20 : $center + $i*20;
return $arr;
}
Than, you can use the function like this:
$PointsArray = pointsArray(50, 5); // {50,70,30,90,10}

Evenly distributed integers within a range

Lets say I have a range between 0 and 100 and I want an array returned containing 3 integers which are evenly distributed within that range, what would be the best way to do this?
For example:
Range: 0-100
Wanted: 3
Returned: 25, 50, 75
Pseudo code:
function distributeIntegers(int wanted, int rangeLow, int rangeHigh)
int increment = (rangeHigh - rangeLow) / (wanted + 1)
array r = new array()
for (int i = rangeLow + increment; i < rangeHigh; i += increment)
r.push(i)
return r
PHP:
function distributeIntegers($wanted = 3, $rangeLow = 0, $rangeHigh = 100){
$increment = ($rangeHigh - $rangeLow) / ($wanted + 1);
$r = array();
for ($i = $rangeLow + $increment; $i < $rangeHigh; $i += $increment)
$r []= $i;
return $r;
}
/*
examples:
call:
distributeIntegers();
returns:
[0] => 25
[1] => 50
[2] => 75
call:
distributeIntegers(4);
returns:
[0] => 20
[1] => 40
[2] => 60
[3] => 80
call:
distributeIntegers(5, 50, 200);
returns:
[0] => 75
[1] => 100
[2] => 125
[3] => 150
[4] => 175
*/
you can make use of array_chunk(), eg only
$end=100;
$a = range(0,$end);
$chunk=3;
foreach (array_chunk($a,$end/($chunk+1)) as $s){
print $s[0]."\n";
}
output
$ php test.php
0
25
50
75
100
you can get rid of the start (0) and end(100) points if not needed.
Here's a solution in groovy that gives the answers you want, you should be able to switch it to whatever language you're using:
def distributedValues(min, max, wanted) {
def incrementBy = (max - min)/(wanted + 1)
(1..wanted).collect { count -> min + (count * incrementBy) }
}
assert distributedValues(0, 100, 1) == [50]
assert distributedValues(0, 100, 3) == [25, 50, 75]
assert distributedValues(0, 100, 4) == [20, 40, 60, 80]
assert distributedValues(0, 100, 5) == [16.6666666667, 33.3333333334, 50.0000000001, 66.6666666668, 83.3333333335]
assert distributedValues(100, 200, 3) == [125, 150, 175]
You can use the rand function to get the random value between the specific ranges.
Use this code . This following function would return set of element in a array
function array_elements( $start = 0 , $end = 100 , $element =5 )
{
$myarray = array () ;
for ( $i = 0 ; $i < $element;$i++ )
{
$myarray[$i]= rand ( $start, $end );
}
return $myarray ;
}
print_r ( array_elements() ) ;

Categories