get lowest value in the array based on variable - php

I am struggling to get the lowest value based on the answer of the client.
$client_answer = 28;
$array = array(10,20,30,40,50);
The answer that should be given is: 20
So every answer should be rounded down to the lower number.
Other examples:
$client_answer = 37;
$array = array(10,20,30,40,50);
answer should be 30.
$client_answer = 14;
$array = array(10,20,30,40,50);
answer should be 10.
$client_answer = 45;
$array = array(10,20,30,40,50);
answer should be 40.
Is there a php function that I can use for this?
If not how can this be accomplished?

You can filter the array to only contain values equal to or below the given value $client_answer, then use max() on the filtered array.
$value = max(array_filter($array, function($v) use ($client_answer) {
return $v <= $client_answer;
}));
Live demo at https://3v4l.org/KHB8r

This might be a very stupid answer, but in this specific case, you are trying to truncate the unit number? Why not try this:
$client_answer = intdiv( $client_answer, 10) * 10;
Divide by 10, get rid of the last digit, and multiply again.
EDIT : typo

Only this rounds correctly
$client_answer = 28;
$array = array(10,20,30,40,50);
rsort($array,1);
$min_diff = max($array);
$closest_val = max($array);
foreach($array as $val)
{
if(abs($client_answer - $val) < $min_diff)
{
$min_diff = abs($client_answer - $val);
$closest_val = $val;
}
}
echo $closest_val;

Related

Consolidate array of numbers without exceeding a predefined maximum value per element

I'm trying to combine numbers in an array by adding them so that the max value can only by 30.
For example, this is my array:
array(10,30,10,10,15);
After combining the numbers in the array to items with a max value 30, the result should be:
array(30,30,15);
How to achieve this?
I'm trying to combine numbers in an array by adding them so that the
max value can only by 30
So, when you combine numbers, you can achieve the lowest possible set of values in your array and also make sure that max value remains 30 by:
First, sort them.
Second, keeping adding elements to sum till you are about to get a sum > 30.
Third, once an element can no longer be added to a sum, add the current sum in your array and make the current element as the new sum.
Code:
<?php
$arr = array(10,30,10,10,15);
sort($arr);
$res = [];
$curr_sum = 0;
foreach($arr as $each_value){
if($curr_sum + $each_value <= 30) $curr_sum += $each_value;
else{
$res[] = $curr_sum;
$curr_sum = $each_value;
}
}
$res[] = $curr_sum;
print_r($res);
Demo: https://3v4l.org/BYhuE
Update: If order of the numbers matters, seeing your current output, you could just use rsort() to show them in descending order.
rsort($res);
$total = array_sum(array(10,30,10,10,15)); //assign sum totals from orignal array
$maxValue = 30; //assign max value allowed in array
$numberOfWholeOccurancesOfMaxValue = floor($total/$maxValue);
$remainder = $total%$maxValue;
//build array
$i=0;
while ( $i < $numberOfWholeOccurancesOfMaxValue ){
$array[] = $maxValue;
$i++;
}
$array[] = $remainder;
print_r($array);
You can loop only once to get this,
$temp = array(10,30,10,10,15);
natsort($temp); // sorting to reduce hustle and complication
$result = [];
$i = 0;
$maxValue = 30;
foreach($temp as $v){
// checking sum is greater or value is greater or $v is greater than equal to
if(!empty($result[$i]) && (($result[$i]+$v) > $maxValue)){
$i++;
}
$result[$i] = (!empty($result[$i]) ? ($result[$i]+$v) : $v);
}
print_r($result);
Working demo.
I believe finding most space-optimized/compact result requires a nested loop. My advice resembles the firstFitDecreasing() function in this answer of mine except in this case the nested loops are accessing the same array. I've added a couple of simple conditions to prevent needless iterations.
rsort($array);
foreach ($array as $k1 => &$v1) {
if ($v1 >= $limit) {
continue;
}
foreach ($array as $k2 => $v2) {
if ($k1 !== $k2 && $v1 + $v2 <= $limit) {
$v1 += $v2;
unset($array[$k2]);
if ($v1 === $limit) {
continue 2;
}
}
}
}
rsort($array);
var_export($array);
By putting larger numbers before smaller numbers before processing AND by attempting to add multiple subsequent values to earlier values, having fewer total elements in the result is possible.
See my comparative demonstration.
I believe #Clint's answer is misinterpreting the task and is damaging the data by summing all values then distributing the max amounts in the result array.
With more challenging input data like $array = [10,30,5,10,5,13,14,15,10,5]; and $limit = 30;, my solution provides a more dense result versus #nice_dev's and #rahul's answers.

PHP Using rand to pick between specific numbers

I know that rand(1,10); would generate a random number between 1 and 30.
How would I go about writing code that would pick a random number out of a group of numbers say 1,7,8 and 9?
Is it possible?
I am pretty sure rand is set up to only generate numbers within a range?
First thing is that rand(1,10) will generate a number between1 to 10 not 1 to 30.
PHP RAND FUNCTION
From a group of numbers, you can generate like this
$numbers = [1,7,8,9];
echo $numbers[rand(0,3)]
You can create custom array which you required, shuffle and get first value
$temp = [1,7,8,9];
shuffle($temp);
echo $temp[0];
shuffle — Shuffle an array
Demo
You could put your group of numbers into an array, and then use array_rand or shuffle to select one of them. For example:
$nums = array(1, 7, 8, 9);
$key = array_rand($nums);
echo $nums[$key] . PHP_EOL;
shuffle($nums);
echo $nums[0] . PHP_EOL;
Demo on 3v4l.org
Use this function (or inline code)
function SelectElementByRandom ( $list )
{
return count($list) ? $list[ rand(0,count($list)-1) ] : NULL;
}
The ?: operator ensures an result (NULL), even if the list is empty.
And for your example:
$result = SelectElementByRandom(array(1,7,8,9));
I would approach it like this. Create a loop that fills an array with random numbers in the range you're looking for (your group of numbers). After that, you choose a random index in that array, which is a random number in your group of numbers.
$min = 0;
$max = 10;
$group_size = 5;
$rand_group = array();
for($i = 0; $i < $group_size; $i++) {
$rand_group[$i] = rand($min,$max);
}
echo $rand_group[rand($min,$max)];

Given an array of integers, what's the most efficient way to get the number of other integers in the array within n?

Given the following array:
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
And assuming $n = 2, what is the most efficient way to get a count of each value in the array within $n of each value?
For example, 6 has 3 other values within $n: 5,7,7.
Ultimately I'd like a corresponding array with simply the counts within $n, like so:
// 0,0,1,2,2,5,6,7,7,9,10,10 // $arr, so you can see it lined up
$count_arr = array(4,4,4,4,4,3,3,4,4,4, 2, 2);
Is a simple foreach loop the way to go? CodePad Link
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
$n = 2;
$count_arr = array();
foreach ($arr as $v) {
$range = range(($v-$n),($v+$n)); // simple range between lower and upper bound
$count = count(array_intersect($arr,$range)); // count intersect array
$count_arr[] = $count-1; // subtract 1 so you don't count itself
}
print_r($arr);
print_r($count_arr);
My last answer was written without fully groking the problem...
Try sorting the array, before processing it, and leverage that when you run through it. This has a better runtime complexity.
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
asort($arr);
$n = 2;
$cnt = count($arr);
$counts = array_pad(array(), $cnt, 0);
for ($x=0; $x<$cnt; $x++) {
$low = $x - 1;
$lower_range_bound = $arr[$x]-$n;
while($low >= 0 && ($arr[$low] >= $lower_range_bound)) {
$counts[$x]++;
$low--;
}
$high = $x + 1;
$upper_range_bound = $arr[$x]+$n;
while($high < $cnt && $arr[$high] <= $upper_range_bound) {
$counts[$x]++;
$high++;
}
}
print_r($arr);
print_r($counts);
Play with it here: http://codepad.org/JXlZNCxW

Calculating the average increase from array values in PHP

I need to calculate the average increase of array values, and I've made a little script which works, but I'd like to know if:
There is a better, more efficient way of doing this
My logic is correct here in calculating the average increase
Lets say I have an array like so:
$array = array(5,10,15,10,0,15);
Lets also imagine that each array item is 1 day, and the value is some counter for that day. I would like to calculate the average increase/decrease in the counter.
What I've done, is looped through the array, and altered the values so that the current item = current item - previous item, what way I'm left with an array which would look like so:
$array = array(5,5,-5,-10,15);
Then I calculate the average as per normal, which in this example would give me a 2 average increase on a daily basis.
Code here:
$array = array(5,10,15,10,0,15);
$count = count($array);
for($i=0;$i<$count;$i++) {
if($i==0) {
$value = $array[$i];
unset($array[$i]);
}
else {
$tmp = $array[$i];
$array[$i] -= $value;
$value = $tmp;
}
}
echo array_sum($array) / count($array);
Is the logic correct here, and is there a more efficient way of doing this, maybe without the loop?
Thanks in advance :)
EDIT: Updated code to account for excluding first value
How about this:
function moving_average($array) {
for ($i = 1; $i < sizeof($array); $i++) {
$result[] = $array[$i] - $array[$i-1];
}
return array_sum($result)/count($result);
}
Try this :
$array = array(5,10,15,10,0,15);
$array2 = $array;
array_pop($array2);
array_unshift($array2, $array[0]);
$subtracted = array_map(function ($x, $y) { return $y-$x; } , $array2, $array);
array_shift($subtracted); /// Comment this if you want six values with 0 as first value
echo array_sum($subtracted) / count($subtracted);
Here's a snazzy one-liner for you:
$days = array(5, 10, 15, 10, 0, 15);
$deltas = array_slice(array_map(function($day1, $day2) {
return $day2 - $day1;
}, $days, array_slice($days, 1)), 0, -1);
var_dump(array_sum($deltas) / count($deltas));
$array = array(5,10,15,10,0,15);
list($prevVal) = array_slice($array, 1);
array_walk($array, function($value, $key, &$prevVal) use(&$array){
if ($key==0) { return; }
$array[$key] = ($value - $prevVal);
$prevVal = $value;
}, $prevVal);
echo array_sum($array) / count($array);
Outputs 1.6666666666667 in float(3.0994415283203E-5)

Compare single value against array - substitute the value for closest number within array

Title is lengthy and confusing, forgive me.
$array = (1,5,10,25,50);
$x = 8
How would I compare $x to each value within the array, and then select the value with the closest match.
In this case, it would be 10.
I imagined creating a handful of if statements but thought there could be a better way to do this.
Thanks in advance
Another way, using an intermediate array with the differences:
$diff = array();
foreach($array as $n)
$diff[$n] = abs($x - $n); // key = number, value = difference
// get the key that contains the smallest difference
$closest = array_search(min($diff), $diff);
$min = 0;
foreach ($array AS $i => $v) {
if (abs($array[$min] - $x) > abs($v - $x))
$min = $i;
// you can optimize this with :
if ($v == $x)
break;
}
$closest = $array[$min];
Something like that should work.

Categories