Calculating Median of an array in PHP - php

I'm trying to figure out how to calculate the median of an array of randomly generated numbers. I have the array all set up, but I'm having trouble putting together a function for the calcuation.
This is what I have so far:
//array
$lessFifty = array();
$moreFifty = array();
//number generation
for ($i = 0; $i<=30; $i++) {
$number = rand(0, 100);
//Sorting <50>
if ($number < 50 ) {
$lessFifty[] = $number;
} else {
$moreFifty[] = $number;
}
}
echo print_r($lessFifty);
echo "<br>" ;
echo print_r($moreFifty);
//Average
echo "<p> Average of values less than fifty: </p>";
print array_sum($lessFifty) / count($lessFifty) ;
echo "<p> Average of values greater than fifty: </p>" ;
print array_sum($moreFifty) / count($moreFifty) ;
//Median
$func = function (median ($array, $output = $median)){
if(!is_array($array)){
return FALSE;
}else{
switch($output){
rsort($array);
$middle = round(count($array) 2);
$total = $array[$middle-1];
break;
return $total;
}
}
echo $func ;
I'm pretty sure that I'm doing this median section completely wrong. I'm just learning and its proving to be a challenge.

Be careful about how you write your for() loop. If you want 30 entries, then you should not use <= or you will end up with 31 because $i starts with 0.
Build an array of the random numbers, then sort them.
Then determine if you have a central entry (odd array length) or if you need to average the middle two entries (even array length).
Here is a modern implementation of a median method posted in 2022 on CodeReview.
Code: (Demo)
$limit = 30; // how many random numbers do you want? 30 or 31?
for ($i = 0; $i < $limit; ++$i) {
$numbers[] = rand(0, 100);
}
var_export($numbers);
//echo "\n---\nAverage: " , array_sum($numbers) / $limit;
echo "\n---\n";
sort($numbers);
$count = sizeof($numbers); // cache the count
$index = floor($count/2); // cache the index
if (!$count) {
echo "no values";
} elseif ($count & 1) { // count is odd
echo $numbers[$index];
} else { // count is even
echo ($numbers[$index-1] + $numbers[$index]) / 2;
}
Possible Output:
array (
0 => 27,
1 => 24,
2 => 84,
3 => 43,
4 => 8,
5 => 51,
6 => 60,
7 => 86,
8 => 9,
9 => 48,
10 => 67,
11 => 20,
12 => 44,
13 => 85,
14 => 6,
15 => 63,
16 => 41,
17 => 32,
18 => 64,
19 => 73,
20 => 43,
21 => 24,
22 => 15,
23 => 19,
24 => 9,
25 => 93,
26 => 88,
27 => 77,
28 => 11,
29 => 54,
)
---
43.5
After sorting, elements [14] and [15] hold 43 and 44 respectively. The average of these "middle two" values is how the result is determined. (Hardcoded numbers demo)
If you want a short, inflexible, hardcoded snippet, then you can use 30 and 14 and 15 as your predetermined size and indexes.
for ($i = 0; $i < 30; ++$i) {
$numbers[] = rand(0, 100);
}
sort($numbers);
echo ($numbers[14] + $numbers[15]) / 2;

Related

Php random number total 3000 [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 12 months ago.
Improve this question
i want to generate 630 random numbers between 1 and 20. So far, so good. However, the sum of the numbers between 1 and 20 of these 630 produced should not exceed 3000. I could not write such an algorithm. Could you help?
Your problem is that 3000 / 630 = 4.76 which is far from the average number between 1-20. What we can do is constrain the random numbers' ranges to accommodate this, and get a distribution slant with an average sum approximate to the maximum sum.
Given the required maximum average of 4.76, we can for example generate 1/4 of the random numbers as between 1-20, and 3/4 as between 1-4 to slant the distribution:
function get_slanted_rands() {
$rands = [];
for($i = 1; $i <= 630; $i++) {
// For every 4th iteration, get random from the full range
$rands[] = $i % 4 === 0
? mt_rand(1,20)
: mt_rand(1,4);
}
$sum = array_sum($rands);
// If the sum is over the max, recall:
if($sum > 3000) {
return get_slanted_rands();
}
// Log the average for debugging:
$avg = round($sum / count($rands), 2);
return compact('sum', 'avg', 'rands');
}
Notice that the function checks the sum and recalls itself on the odd occasion that the sum exceeds 3000. On a typical call, the sum 3000 isn't exceeded with the above "calibration" — since we split 1:3 in favor of the lower range. But random is random, so there's no "average" guaranteed.
Let's test-drive this contraption for 100 iterations and see what we get:
$test = [];
for($t = 1; $t <= 100; $t++) {
$test[] = get_slanted_rands();
}
$sums = array_column($test, 'sum');
rsort($sums);
echo "==== SUMS ====\n" . implode(', ', $sums) . "\n\n";
$avgs = array_column($test, 'avg');
rsort($avgs);
echo "==== AVGS ====\n" . implode(', ', $avgs);
This yields for the following (reverse sorted), sums between 2600+ and 3000 and averages between 4.75 and 4.19. (On average, ~1:100 iterations exceeds 3000 and is recalled.)
==== SUMS ====
2993, 2985, 2975, 2969, 2959, 2947, 2941, 2933, 2926, 2919, 2919, 2917, 2911, 2909, 2908, 2904, 2903, 2901, 2894, 2894, 2892, 2886, 2884, 2884, 2882, 2881, 2879, 2876, 2871, 2869, 2867, 2863, 2861, 2853, 2852, 2852, 2851, 2851, 2850, 2848, 2844, 2843, 2842, 2838, 2838, 2837, 2837, 2837, 2836, 2834, 2834, 2826, 2826, 2825, 2820, 2814, 2813, 2812, 2802, 2801, 2799, 2799, 2799, 2798, 2796, 2795, 2792, 2789, 2789, 2787, 2784, 2784, 2784, 2783, 2778, 2778, 2776, 2768, 2767, 2764, 2762, 2754, 2754, 2747, 2743, 2737, 2736, 2728, 2727, 2724, 2723, 2721, 2719, 2718, 2707, 2706, 2690, 2673, 2642
==== AVGS ====
4.75, 4.74, 4.72, 4.71, 4.7, 4.68, 4.67, 4.66, 4.64, 4.63, 4.63, 4.63, 4.62, 4.62, 4.62, 4.61, 4.61, 4.6, 4.59, 4.59, 4.59, 4.58, 4.58, 4.58, 4.57, 4.57, 4.57, 4.57, 4.56, 4.55, 4.55, 4.54, 4.54, 4.53, 4.53, 4.53, 4.53, 4.53, 4.52, 4.52, 4.51, 4.51, 4.51, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.49, 4.49, 4.48, 4.48, 4.47, 4.47, 4.46, 4.45, 4.45, 4.44, 4.44, 4.44, 4.44, 4.44, 4.44, 4.43, 4.43, 4.43, 4.42, 4.42, 4.42, 4.42, 4.42, 4.41, 4.41, 4.41, 4.39, 4.39, 4.39, 4.38, 4.37, 4.37, 4.36, 4.35, 4.34, 4.34, 4.33, 4.33, 4.32, 4.32, 4.32, 4.32, 4.31, 4.3, 4.3, 4.27, 4.24, 4.19
You can always tweak the slanting condition if you feel it should on average be closer to 3000... Or simply add a recall condition with a "minimum sum" check and "brute force" it. But this suffices to give you the general idea: You need to generate random numbers of a limited range in proportion to what your "average for target sum" demands. Demo at 3v4l: https://3v4l.org/fG74X
Finally, a sample of the sort of distribution you get. Given as "number" => "instances" in a set of 630. It's heavily slanted to 1, 2, 3, 4 there — and that's how it must be to meet your specs!
$nums = get_slanted_rands();
$distribution = array_count_values($nums['rands']);
arsort($distribution);
print_r($distribution);
// yields:
[3] => 143
[4] => 125
[2] => 125
[1] => 110
[8] => 13
[9] => 12
[18] => 12
[19] => 10
[11] => 9
[5] => 8
[17] => 8
[14] => 7
[12] => 7
[10] => 7
[16] => 7
[6] => 7
[15] => 6
[7] => 6
[20] => 5
[13] => 3
$result = [];
$sumCurrent = 0;
$barrier = 3000 / 630;
for ($i = 1; $i <= 630; $i++) {
$sumBarrier = intval($i * $barrier);
while (true) {
$number = random_int(1, 20);
if ($sumCurrent + $number <= $sumBarrier) {
break;
}
}
$result[] = $number;
$sumCurrent += $number;
}
$sum = array_sum($result);
$occurrences = array_count_values($result);
uksort($occurrences, fn($key1, $key2) => $key1 <=> $key2);
print_r($result); echo "\n";
print_r($sum); echo "\n";
print_r($occurrences); echo "\n";

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..

PHP array read out succession

In PHP I have an Array like this:
$BulkArray[$i]
This Array is feed with plenty of Numbers (e.g. 1 => 100, 2 => 300, 3 => 100, and so on).
Now I want to find within the whole range of numbers, the greatest succession of a number equal or less than 500. I want to write the number of succession.
for example I have the array
1 => 100, 2 => 300, 3 => 100,
4 => 50, 5 => 50, 6 => 50, 7 => 50, 8 => 50,
9 => 500, 10 => 200, 11 => 100
as you can see, number 1,2 & 3 are together 500. So this is the first succession.
2,3,4,5 are also 500 together. (This succession(4) is bigger than the first succession(3))
And so on,then you will get the highest succession: 3,4,5,6,7,8 (succession with 6 numbers) which is 350 (but lower than 500m, as we searched for it)
Now, how can I write with the Array:
$BulkArray[$i], that the highest succession is 6 ?
Because 6 is the highest succession found in the whole array for 500!
(It's for categorizing specific Carparts)
The answer of User "fas M" here again, with little improvement:
<?php //lets call your $BulkArray = $values;
$values=array( 1 => 100, 2 => 300, 3 => 100,
4 => 50, 5 => 50, 6 => 50, 7 => 50, 8 => 50,
9 => 500, 10 => 200, 11 => 100 );
$sum=0; // to sum up until 500
$Vals500=array(); // array to store index with <= 500
$i=0; // index for new aaray that will store keys that made up <= 500
$key1=1; //value to iterate the array defined above
for($key=1; $key <= count($values); $key++){
$sum = $sum + $values[$key]; // get sum of values
if($sum <= 500){ $Vals500[$i][]=$key; } //append all key of sum ==500
if($sum >= 500) { $i++; $key=$key1++; $sum=0; } //check sum then reintialize
//added bigger equal
}
echo count(max($Vals500)); // read out the biggest succession
?>
Thanks again to fas M !
Click Here or here you can see somehing
<?php //lets call your $BulkArray = $values;
$values=array( 1 => 100, 2 => 300, 3 => 100,
4 => 50, 5 => 50, 6 => 50, 7 => 50, 8 => 50,
9 => 500, 10 => 200, 11 => 100 );
$sum=0; // to sum up until 500
$Vals500=array(); // array to store index with <= 500
$i=0; // index for new aaray that will store keys that made up <= 500
$key1=1; //value to iterate the array defined above
//print_r($values); echo '<br/>';
for($key=1; $key <= count($values); $key++){
$sum = $sum + $values[$key]; // get sum of values
if($sum <= 500){ $Vals500[$i][]=$key; } //append all key of sum ==500
if($sum == 500) { $i++; $key=$key1++; $sum=0; } //check sum then reinitialize values
}
foreach($Vals500 as $val){} //search for second array with many indeces in $Vals500. NB: i fail this place
echo print_r($Vals500);
print 'the highest succession found is '; print_r($Vals500[2]); //
?>

taking value to next 10th position

I know that it's rather an unusual question, but I need to find next 10th position
Let me clear with an example:
I will have some numbers like
2, 5, 8, 13, 28, 35, 42, 49
I want to find the next 10th position
2 => 10
5 => 10
8 => 10
13 => 20
28 => 30
35 => 40
42 => 50
49 => 50
How can I find it, please help guys. thanks.
Sorry for poor english.
Divide by 10, ceil(), multiply by 10.
$next10th = round( $number + 5 , -1 , PHP_ROUND_HALF_DOWN )
If the number is integer, you can also use:
$next10th = $number + 9 - (($number-1) % 10)
$numbers = array(2, 5, 8, 13, 28, 35, 42, 49);
foreach ($numbers as $n) {
echo $n . ' => ' . ((floor($n / 10) + 1) * 10) . "<br />\n";
}
or
$numbers = array(2, 5, 8, 13, 28, 35, 42, 49);
foreach ($numbers as $n) {
echo $n . ' => ' . (ceil($n / 10) * 10) . "<br />\n";
}
Both output:
2 => 10
5 => 10
8 => 10
13 => 20
28 => 30
35 => 40
42 => 50
49 => 50

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