Basically I wondering the best approach to determine a score based on a range defined in an array
I have a set of values ranging between 300 and 900 , each value has a corresponding percentile range.
I want to create a function that gives you the percentile based on the value checked. The value passed into the function may not match the defined value in the array, but want to return the highest percentile for that value.
For example in the array will be something like
'300'=>'10', '333'=>'11', '340' => '12' .... '900'=>'100'
IF I pass in 335, then the function should return 11. Not sure simplest approach.
You can easly loop .. but if you don't want to do that then you can use
$var = 335 ;
$array = array('300'=>'10', '333'=>'11', '340' => '12');
echo getPercentage($array,$var);
Output
11
Function Used
function getPercentage(array $a, $v) {
if (array_key_exists($v, $a)) {
return $a[$v];
}
$a[$v] = null;
ksort($a);
$pos = array_search($v, array_keys($a));
$pos = array_slice($a, (($pos == 0) ? 1 : $pos - 1), 1);
return reset($pos);
}
If the array is ordered, it's straightforward. If you start at the bottom (score = 300) then go up until your score is larger than the array score, and the correct percentile is the one you just passed on the way up. If you start at the top, go down until your score is lower than the array score, and the correct percentile is the one you just passed on the way down.
Starting at the top or bottom of your array based on the score may give you a slight performance gain.
You can do it this way:
<?php
function get_percentile($val){
$arr = array('300'=>'10', '333'=>'11', '340'=>'12');
while(!$arr[$val]){
$val--;
}
return $arr[$val];
}
echo get_percentile(335);
?>
Output:
11
Check it out!
Related
I have this array:
Array
(
[10:00:00] => 15
[10:30:00] => 15
[11:00:00] => 8
)
I need to see if any of them equal 15, if so do something.
There will be more items being added in the future. The items are all time slots and the number on the right is the amount of bookings. No more than 15 bookings per time slot.
The times will go into a form as select options. I either need to show all and disable the fully booked ones, or only show the available slots.
The other way it could be done is by looking for all the ones that don't equal 15 and then adding them to the select.
I will of course include some server side validation to stop more than 15 being allocated to a time slot.
This is one way of doing it ...
if (in_array(15, $myArray)) {
// Do something
}
... as #AbraCadaver mentioned, it is from the official PHP manual at https://php.net/manual/en/function.in-array.php
To get an array of all of those NOT equal to 15:
$result = array_filter(function($v) { return $v != 15; }, $array);
To check if a value is in an array you can use in_array, however for your use case you are looking to eliminate ALL of the 15 values from your select. So just build an array of what you want.
Andreas's comment didn't occur to me at first but is how I would normally do it:
$result = array_diff($array, [15]);
You could use array_count_values() along with isset().
if(isset(array_count_values($myArray)[15])) {
//do something
}
Basically, array_count_values() will return an array, which, with your example would be:
[15 => 2, 8 => 1]
Which is just how many times each value appeared in the original array. Then we use isset() to check if the key 15 exists in the output from array_count_values().
There are different build in methods in php to solve this.
some of them are.
in_array
array_search
array_filter
array_reduce
array_diff
array_intersect
here is how you do on them
in_array
if (in_array(15, $array)) // do your stuff here
array_search
if (array_search(15, $array) !== false) // do your stuff here
array_filter
if (! empty(array_filter($array, function ($a) { return $a == 15; })) // do your stuff here
array_reduce
if (array_reduce($array, function ($c, $d) { return $c = $c == 15 || $d == 15 ? 15 : 0; }) -- 15) // do your stuff here
array_diff
if (count(array_diff($array, [ 15 ])) != count($array)) // do your stuff here
array_intersect
if (! empty(array_intersect($array, [15]))) // do your stuff here
There are many more methods, depending on the logic you use.
Since you want to show a select box, you will need to iterate over the array anyway. The only senseful condition before doing so could be whether or not already all slots are booked. Then you might not want to show the <select> at all but some notice instead. Looking if at least one is 15 does not seem to make sense.
count($slots) === (array_count_values($slots)[15]??0) is true when all slots are booked.
The complete code generating enabled/disabled <options> or no <select> box at all could look like:
$slots =
[
'10:00:00' => 15,
'10:30:00' => 15,
'11:00:00' => 8,
];
if(count($slots) === (array_count_values($slots)[15]??0))
{
?>
<div>No slots are available anymore.</div>
<?php
}
else
{
?>
<select name="slot">
<option value="">select a time slot</option>
<?php
foreach ($slots as $k=>$v)
{
$avail = 15-intval($v);
?>
<option value="<?php echo $k;?>"<?php if($avail < 1) echo ' disabled'?>><?php echo "$k ($avail available)";?></option>
<?php
}
?>
</select>
<?php
}
For example i have an array like this [-1,-1,-1,-1,-1,-1,2.5,-1,-1,8.3]
I want to count the element which are not -1 like except of the -1. Is there any function in php to get this ? One approach which i think is
Count the total array - count of the -1 in the array.
how can we achieve this.
P.S : please provide me a comment why this question deserve negative vote.
Like #MarkBaker said, PHP doesn't have a convenient function for every single problem, however, you could make one yourself like this:
$arr = [-1,-1,-1,-1,-1,-1,2.5,-1,-1,8.3];
function countExcludingValuesOfNegativeOne ($arr) {
return count($arr) - array_count_values(array_map('strval', $arr))['-1'];
}
echo countExcludingValuesOfNegativeOne($arr); // Outputs `2`.
It just counts the whole array, then subtracts the number of negative 1s in the array. Because PHP throws an error if any element in the array isn't a string 1 when using array_count_values, I've just converted all elements of the array to a string using array_map('strval', $arr) 2
you can use a for loop counter skipping for a specific number.
function skip_counter($array,$skip){
$counter = 0;
foreach ($array as $value) {
if ($value != $skip) $counter++;
}
return $counter;
}
then you call skip_counter($your_list, $number_to_be_skipped);
$arr = array(
1, 1, 2, 3, 4
);
How to find out the pair from this array ?
Keep in mind that the pair from array could be any number (1,2,4,3,2) or (3,3,1,2,4); I just give an random example above.
if there is a pair in array
echo "The pair number is 1";
All of my methods will return the desired result as long as there IS a duplicate. It is also assumed because of your sample input, that there is only 1 duplicate in the array. The difference between my methods (and the other answers on this page) will be milliseconds at most for your input size. Because your users will not be able to distinguish between any of the correct methods on this page, I will suggest that the method that you implement should be determined by "readability","simplicity", and/or "brevity". There are many coders who always default to for/foreach/while loops. There are others who always defer to functional iterators. Your choice will probably just come to down to "your coding style".
Input:
$arr=[1,1,2,3,4];
Method #1: array_count_values(), arsort(), key()
$result=array_count_values($arr);
arsort($result); // this doesn't return an array, so cannot be nested
echo key($result);
// if no duplicate, this will return the first value from the input array
Explanation: generate new array of value occurrences, sort new array by occurrences from highest to lowest, return the key.
Method #2: array_count_values(), array_filter(), key()
echo key(array_filter(array_count_values($arr),function($v){return $v!=1;}));
// if no duplicate, this will return null
Explanation: generate the array of value occurrences, filter out the 1's, return the lone key.
Method #3: array_unique(), array_diff_key(), current()
echo current(array_diff_key($arr,array_unique($arr)));
// if no duplicate, this will return false
Explanation: remove duplicates and preserve the keys, find element that went missing, return the lone value.
Further consideration after reading: https://www.exakat.io/avoid-array_unique/ and the accepted answer from array_unique vs array_flip I have a new favorite 2-function one-liner...
Method #4: array_count_values(), array_flip()
echo array_flip(array_count_values($arr))[2];
// if no duplicate, this will show a notice because it is trying to access a non-existent element
// you can use a suppressor '#' like this:
// echo #array_flip(array_count_values($arr))[2];
// this will return null on no duplicate
Explanation: count the occurrences (which makes keys of the values), swap the keys and values (creating a 2-element array), access the 2 key without a function call. Quick-smart!
If you wanted to implement Method #4, you can write something like this:(demo)
$dupe=#array_flip(array_count_values($arr))[2];
if($dupe!==null){
echo "The pair number is $dupe";
}else{
echo "There were no pairs";
}
There will be many ways to achieve your desired result as you can see from all of the answers, but I'll stop here.
First sort your array, then use foreach loop and if current and next are equal and not echo this item before this time, echo item is pair.
$arr = array(
1, 3, 1, 2, 2, 2, 3, 4
);
sort($arr);
$last_number = null;
foreach($arr as $key => $item) {
if(array_key_exists($key + 1, $arr)) {
if($item === $arr[$key + 1]) {
if($last_number !== $item) {//prevent duplicate echo pair of one item
echo 'The pair number is ' . $item;
$last_number = $item;
}
}
}
}
Use built-in array_count_values. Then iterate over results and check if count is greater than 1.
$arr = array(
1, 1, 2, 3, 4
);
$values = array_count_values($arr);
foreach ($values as $key => $value) {
if ($value > 1) {
echo 'Pair: ' . $key;
// break, if you need to show first pair only
// break;
}
}
You can first count all the values in the array, then for each distinct value check if it occurs twice in the array.
<?php
$array = array(1, 1, 2, 3, 4);
$vars = array_count_values($array);
foreach($vars as $key => $var) {
if($var == 2) {
echo "The pair number is " . $key . "<br>";
}
}
?>
First sort the array, then check if there are two numbers on consecutive indexes with the same value.
This is the most efficient solution: sorting is done in O(n log n) time1 and doing the checking takes O(n) time. Overall, you'll have the answer in O(n log n) time. Naive approaches will use O(n2) time.
If you don't want to modify the original array, do all of the above on a copy.
function hasEqualPair($arr) {
sort($arr);
$l = count($arr);
for ($i = 1; $i < $l; ++$i) {
if ($arr[$i] === $arr[$i - 1]) {
return true;
}
}
return false;
}
var_dump(hasEqualPair(array(1, 2, 4, 3, 2))); // true
var_dump(hasEqualPair(array(1, 1, 2, 3, 4))); // true
var_dump(hasEqualPair(array(3, 3, 1, 2, 4))); // true
var_dump(hasEqualPair(array(3, 5, 1, 2, 4))); // false
Try it online!
Of course, if you want to know what the pair is, just change return true in the above function to return $arr[$i]. You then might want to change the function name to getEqualPair as well.
1 The sort function in PHP uses Quicksort. It is possible to make that always run in O(n log n) time, but the implementation in PHP probably has an average running time of O(n log n), with worst case running time still O(n2).
$arr = array(
1, 1, 2, 3, 4
);
echo "<pre>";
$vals = array_count_values($arr);
foreach ($vals as $key => $value) {
if($value%2==0){
echo "The pair number is ".$key."<br>";
}else{
echo "The not pair number is ".$key."<br>";
}
}
I'm trying to make a simple PHP script for school. I need to output 2 random students from the array $leerlingen (Leerlingen = students).
It work's fine when I use echo $leerlingen within the foreach loop, but when I use the return statement it stops executing, because when return is used, it ends the function.
Code:
$leerlingen = array("tobias", "hasna", "aukje", "fred", "sep", "koen", "wahed", "anna", "jackie", "rashida", "winston", "sammy", "manon", "ben", "karim", "bart", "lisa", "lieke");
shuffle($leerlingen);
function maakGroepjes($leerlingen) {
$begin = 1;
foreach ($leerlingen as $leerling) {
if ($begin <= 2) {
echo $leerling;
$begin++;
}
}
}
echo maakGroepjes($leerlingen);
Can anyone tell me how to solve this problem?
You can return only one value inside a function, in this case is an array. I assume that the array have at least two values.
<?php
$leerlingen = array(
"tobias", "hasna", "aukje", "fred", "sep", "koen", "wahed", "anna", "jackie", "rashida", "winston", "sammy", "manon", "ben", "karim", "bart", "lisa", "lieke"
);
shuffle($leerlingen);
function maakGroepjes($leerlingen) {
//your result array
$result = array();
//Picking 2 random entries out of an array to $keys
$keys = array_rand($leerlingen, 2);
//Returning the array with two values
return array($leerlingen[$keys[0]], $leerlingen[$keys[1]]);
}
//assign the values to the vars
list($one, $two) = maakGroepjes($leerlingen);
//printing
echo $one . "<br>\n";
echo $two . "<br>\n";
?>
array_rand and other functions (rand) that rely on libc have a bad standard distribution. I'd always recommend using mt_rand() if you need it to be equally distributed, otherwise some entries will be heavily favored.
This is a good easy replacement for numerical arrays:
function array_mt_rand($array) {
return $array[ mt_rand( 0, count($array)-1 ) ];
}
$one = array_mt_rand($array);
$two = array_mt_rand($array);
You may need some extra checks if you have a small array and always want two distinct values though.
You could always try something like this.
function maakGroepjes($leerlingen) {
do {
$first_student = array_rand($leerlingen);
$second_student = array_rand($leerlingen);
} while ($leerlingen[$first_student] == $leerlingen[$second_student]);
return [$leerlingen[$first_studen], $leerlingen[$second_student]];
}
Which returns this.
Array
(
[0] => manon
[1] => winston
)
Also, the difference between a function printing/echo'ing information and returning information is pretty big.
You can't assign a variable to the echo statement inside of a function, whereas you could assign a variable to the return statement.
I would approach this a little differently.
function maakGroepjes($leerlingen) {
shuffle($leerlingen); // randomize the list of students
return array_chunk($leerlingen, 2); // break in into groups of two and return it
}
Then with
$groepjes = maakGroepjes($leerlingen);
you can generate all of the groups at once. No worries about repetition. This way if you need multiple groups, you can loop over the list of groups. If you really only need one group of two, then that will be
$groepjes[0];
which you can ouptut however you like. A very simple example:
foreach ($groepjes[0] as $student) echo "$student<br>";
Try this:
if ($begin <= 2) {
echo $leerling;
$begin++;
} else {
return
}
What this does is: every time through the loop, it looks at $begin. If it's less than or equal to two, it echoes that student and increments $begin. Otherwise, if it's greater than two, it returns, ending the function (and thus, the loop).
A perhaps better way to do it would be to just look at the ordinal directly:
foreach ($leerlingen as $ord => $leerling) {
echo $leerling;
if ($ord == 1) return;
}
Note the syntax in the loop definition. The "old =>" part sets the ordinal value as a variable as you loop through, letting you see which entry in the array you are currently on. So, this just loops through printing students. When it has printed the second student (remember, arrays are counted 0, 1, 2...) it returns.
Also, you probably don't want to echo maakGroepjes(). That function is what is echoing the student names. You probably don't want to echo the function result unless the function compiles the names into a string and returns the string or something.
How to get random value from array set an value in array that will be one to selected more than other?
array('00','01','02');
I want to select an random value from this array with most selected value be '00', i.e the '00' value will be selected 80% and other two values will be 20%.
Here array can have many values, its only an example with three values
$main_array=array('00','01','02');
$priority=array(0,0,0,0,0,0,0,0,1,2);
$rand_index=array_rand($priority);//select a random index from priority array.. $priority[$rand_index] will give you index 0 or 1 or 2 with your priority set..
echo $main_array[$priority[$rand_index]];
I think the code is self explanatory...
Array will have many elements case will come when lets say the requirement will come like 3% probability of "00" 28% prob. of "01" rest to other elements...In that case use array_fill function to fill elements in masses...and array_merge them
Like for the same case I've taken answer will be
$main_array=array('00','01','02');
$priority1=array_fill(0,69,2);
$priority2=array_fill(0,28,1);
$priority3=array_fill(0,3,0);
$priority=array_merge($priority1,$priority2,$priority3);
$rand_index=array_rand($priority);
echo $main_array[$priority[$rand_index]];
Here's an idea.
$arr = array('00', '01', '02');
$randInt = rand(1, 10);
if ($randInt <= 8) {
$value = $arr[0];
}
else if ($randInt == 9) {
$value = $arr[1];
}
else { // ($randInt == 10)
$value = $arr[2];
}
There is now an 80% chance that $value contains '00', a 10% chance that it contains '01', and a 10% chance it contains '02'. This may not be the most efficient solution, but it will work.
one of many options
$a = array_fill(0, 8, '0');
$a['9']='1';
$a['10']='2';
echo $a[array_rand($a,1)];
Use a parallel array with the probability distribution, e.g.:
array('80', '10', '10');
Use standard random number function to generate a number between 0 and 99, then look it up in this array. The index you find it at is then used as the index to the values array.