Find key of array based on variable value between array values [duplicate] - php

This question already has answers here:
Find a matching or closest value in an array
(13 answers)
Closed 7 years ago.
I need to find the left-near key of a base array corresponding to a variable value.
Searched value (in this case) is always between 1 and 779
Better with an example:
$fixedArr = [ 0, 5, 8, 20, 40, 60, 90, 135, 780 ];
$search = 42; // $result = $arr[4] -> 4;
$search = 110; // $result = $arr[6] -> 6;
$search = 134; // $result = $arr[6] -> 6;
$search = 135; // $result = $arr[7] -> 7;
I try with a foreach loop but with no luck, any idea??
Thanks

searched value is always between (in this case) 1 and 779
$fixedArr = [ 0, 5, 8, 20, 40, 60, 90, 135, 780 ];
$search = 42;
for ($i = 0; $i < count($fixedArr); $i++)
if ($search < $fixedArr[$i]) break;
echo $i-1;

This maybe help you;
$fixedArr = [ 0, 5, 8, 20, 40, 60, 90,135,780 ];
//
$search = 111; // $result = $arr[4] -> 4;
//$search = 110; // $result = $arr[6] -> 6;
//
function leftORright($fixedArr,$search){
$max = max($fixedArr)+1;
$near = array(
'left'=>array('key'=>'none','value'=>'none','bool'=>false),
'right'=>array('key'=>'none','value'=>$max,'bool'=>false),
'center'=>array('key'=>'none','value'=>'none','bool'=>false)
);
foreach($fixedArr as $k=>$v){
if($v == $search){
$near['center']['key'] = $k;
$near['center']['value'] = $v;
}
if($v < $search){
$near['left']['key'] = $k;
$near['left']['value'] = $v;
}
if($v > $search and $near['right']['value'] > $v){
$near['right']['key'] = $k;
$near['right']['value'] = $v;
}
}
//decide near left or right
$respright = $near['right']['value'] - $search;
$respleft = $search - $near['left']['value'] ;
$right_left_equals = false;
if($near['center']['value'] !== 'none'){
$near['center']['bool'] = true;
}else if($respleft < $respright && $near['left']['key']!='none'){
$near['left']['bool'] = true;
}else if($respleft > $respright && $near['right']['key']!='none'){
$near['right']['bool'] = true;
}else if($near['center']['value'] != 'none'){
$near['center']['value'] = true;
}else{
$right_left_equals = true;
}
//var_dump($near);
//Result is:
foreach($near as $k=>$v){
foreach($v as $k2=>$v2){
if($v2===true){
var_dump('near is for '.$k);
return $v;
}
}
}
//equal for right and left
if($right_left_equals){
var_dump('near right left are equals');
return array($near['right'],$near['left']);
}
}
$result = leftORright($fixedArr,$search);
var_dump($result);
response:
string 'near is for left' (length=16)
array (size=3)
'key' => int 6
'value' => int 90
'bool' => boolean true

Use array_search:
array_search — Searches the array for a given value and returns the corresponding key if successful
$search = array_search(42, $fixedArr); // -> 4
$search = array_search(110, $fixedArr); // -> 6
Your question is similar to finding the closest one:
<?php
$fixedArr = [ 0, 5, 8, 20, 40, 60, 90, 135, 780 ];
function getClosest($search, $arr) {
$left = 0;
foreach ($arr as $val) {
if ($search > $val)
$left = $val;
elseif ($search < $val) {
$right = $val;
break;
}
else {
$right = $val;
break;
}
}
return array($left, $right, array_search($left, $arr), array_search($right, $arr), (($search - $left) > ($right - $search) ? array_search($right, $arr) : array_search($left, $arr)));
}
print_r(getClosest(4, $fixedArr));
?>

Try this : It will Work in all cases.
$fixedArr = [ 0, 5, 8, 20, 40, 60, 90, 135, 780 ];
$find = 14;
for ($i=0; $i < count($fixedArr); $i++) {
if($fixedArr[$i] <= $find){
$large[] = $fixedArr[$i];
}else{
$small[] = $fixedArr[$i];
}
}
$near1 = max($large);
$near2 = min($small);
echo "Value $find coming in between $near1 and $near2";
echo "<br>";
if($find >= ($near1 + $near2) / 2){
echo "Closed Value is : $near2";
}else{
echo "Closed Value is : $near1";
}
Output:
Value 14 coming in between 8 and 20
Closed Value is : 20

Related

How to condense an array of integers in PHP?

So I have an array of integers: <1, 2, 3, 9, 10, 11, 14>, that I would like to join together in this format: <1-3, 9-11, 14>.
I'm new to PHP and tried doing this by looping through the array:
function pasteTogether($val)
{
$newVals = array();
$min = $val[0];
$max = $val[1];
$counter = 0;
for ($i = 0; $i < count($val); $i++)
{
if ($val[$i + 1] === $val[$i] + 1)
{
$max = $val[$i + 1];
}
else
{
$tempVal = $min."-".$max;
$newVals[$counter] = $tempVal;
$counter++;
$min = $val[$i];
}
}
return $newVals;
}
However, when I run this code, I get <1-3, 3-11, 11-11, 14-14>
PHP Fatal error: Maximum execution time of 30 seconds exceeded in ../learning.php on line 36
Because the for loop never ends you increment $val instead of $i
$array = array(1, 2, 3, 9, 10, 11, 14);
function pasteTogether($val)
{
$newVals = array();
$min = $val[0];
$max = $val[1];
$counter = 0;
for ($i = 0; $i < count($val); $i++)
{
if ($val[$i + 1] === $val[$i] + 1)
{
$max = $val[$i + 1];
}
else
{
$tempVal = $min."-".$max;
$newVals[$counter] = $tempVal;
$counter++;
$min = $val[$i];
}
}
return $newVals;
}
pasteTogether($array);
I have been playing around with this interesting problem and found another solution. So, if anyone is interested:
$arr=array(1, 2, 3, 9, 10, 11, 14, 15, 16, 18);
$v0=$dif=null;$rows=array();
foreach ($arr as $i => $v) {
if ($dif!=($d=($v-$i))){
if ($v0) $rows[]="$v0-".$arr[$i-1];
$v0=$v;
$dif=$d;
}
}
$rows[]="$v0-".($d==$dif?$arr[$i]:$v0);
print_r($rows);
I added a few numbers to the array and the result is this:
$rows = Array
(
[0] => 1-3
[1] => 9-11
[2] => 14-16
[3] => 18-18
)
You can find a little demo here: http://rextester.com/ABC25608
This works:
function pasteTogether($val)
{
$compacted = [];
$min = null;
$max = null;
$format = function ($a, $b) {
return ($a < $b ? "$a-$b" : $a);
};
foreach ($val as $current) {
if ($min === null) {
$min = $current;
$max = $current - 1;
}
if ($current == $max + 1) {
$max++;
} else {
$compacted[] = $format($min, $max);
$min = $current;
$max = $current;
}
}
$compacted[] = $format($min, $max);
return $compacted;
}
echo '<', implode(', ', pasteTogether([1, 2, 3, 9, 10, 11, 14])), '>';
Output:
<1-3, 9-11, 14>

PHP foreach reset and remove/subtract array values if condition is true

If I have following value, $result = 0, $request = 50 and $array = [25, 20], How do I reset and subtract $request value to
$array values if $request value is greater than $array. and foreach will break if condition are
$request less than $array value or, $request = 0 or, $array values = 0.
So condition like this and $result will be 5.
50 - [25, 20]
|___ >= __| |
25 00 |
|_ >= ________|
5 00
code:
while(true) {
$reset = false
$result = 0;
foreach($array as $key => $value) {
if($request >= $value) {
....
} else {
....
$reset = true;
break;
}
}
if(!$reset) {
break;
}
}
$request will be same as $result, so it's the same thing and therefore not needed.
$request = 50;
$array = array(25, 20);
foreach($array as $key => $value) {
if($request < $value || $request === 0 ) {
break;
}
$request = $request - $value;
}
echo 'Result: '.$request;
TESTS
$request = 50;
$array = array(25, 20);
// Result: 5
$array = array(25, 30);
// Result: 25
$array = array(25, 25);
// Result: 0
$array = array(51, 10);
// Result: 50
EDIT
Edit based on comments and OP fiddle.
$request = 50;
$array = array(20, 25, 25);
$excess = max(array_sum($array) - $request, 0);
foreach($array as $key => $value) {
if($request < $value || $request === 0 ) {
$request = 0;
break;
}
$request = $request - $value;
}
echo 'Result: '.$request.'<br />';
echo 'excessValue: '.$excess;
TESTS
$request = 50;
$array = array(25, 20);
// Result: 5, excess: 0
$array = array(50, 20);
// Result: 0, excess: 20
$array = array(52, 5);
// Result: 0, excess: 7
$array = array(20, 25, 25);
// Result: 0, excess: 20
<?php
while(true) {
$reset = false;
$result = 0;
$request = 51;
$array = array(25, 20);
foreach($array as $value) {
if($request>=$value){
$request=$request-$value;
}
else{
break;
}
echo 'Result: '.$request;
}
if(!$reset) {
break;
}
}
?>

PHP Array Keep Data and Calculating By Its Index

I have a list of number in array. Here's my example data:
Person 1 => 20, 40, 50
Person 2 => 10, 20, 40
Person 3 => 20, 20, 30
I want to ask, how to put their scores to an array and calculate it by it index? My code to create this array:
$indeksarr = 1;
$temparr[$indeksarr] = array();
$num = 3;
while($grade = $query->fetch_array()) <-- basically get score from DB (only return score for each student)
{
for($i=1; $i <= $num; $i++)
{
$newdata = array($indeksarr => $grade);
$temparr[$indeksarr][] = $newdata;
$indeksarr++;
}
}
for($i=1; $i <= $num; $i++)
{
print_r($temparr[$i]);
}
My code result:
Result[1] = 20
Result[2] = 10
The result that I want:
Result[1] = 50 ( <- 20+10+20 ) <- all from array index 1
Result[2] = 80 ( <- 40+20+20 ) <- all from array index 2
Result[3] = 120 ( <- 50+40+30 ) <- all from array index 3
Any idea to fix my array?
Please try below code once, it might help for dynamic values also.
while ($grade = $query->fetch_array()) {
//$grdata = explode(",", $grade); // if those are comma separated values
$grdata = $grade;
for ($j = 0, $k = 1; $j < count($grdata); $j++, $k++) {
if (isset($temparr[$k])) {
$temparr[$k] = $temparr[$k] + $grdata[$j];
} else {
$temparr[$k] = $grdata[$j];
}
}
}
print_r($temparr);
biuld array like below
$persons = array('Person1'=>array(20,40,50),'Person2' => array(10, 20, 40),'Person3' => array(20, 20, 30));
//than perform below function
$array_sum = array_reduce($persons,"abb");
function abb($a,$b)
{
foreach($b as $key=>$value)
{
if(isset($a[$key]))
$a[$key] += $value;
else
$a[$key] = $value;
}
return $a;
}
var_dump($array_sum);
o/p
array (size=3)
0 => int 50
1 => int 80
2 => int 120
try this:
$result = array();
$start_index = 1;
$stop_index = 3;
while($grade = $query->fetch_array()) //<-- basically get score from DB (only return score for each student)
{
// grade = array('Person 1' => array(20,10,20));
$values = array_values($grade);
$result[$start_index] = array_sum($values[0]);
if ($start_index == $stop_index) break; // stop when it reach stop_index
$start_index++;
}
echo "<pre>";
print_r($result);
echo "</pre>";
die;
Here's a simple alternative using array_walk and array_sum:
$subTotal = [[0,0,0],[0,0,0],[0,0,0]];
$line = 0;
function walk($item, $key) {
global $subTotal;
global $line;
$subTotal[$key][$line] = $item;
}
$array = [
[20, 40, 50],
[10, 20, 40],
[20, 20, 30]
];
$finalArray = [];
array_walk($array[0], 'walk');
$line = 1;
array_walk($array[1], 'walk');
$line = 2;
array_walk($array[2], 'walk');
$finalArray[] = array_sum($subTotal[0]);
$finalArray[] = array_sum($subTotal[1]);
$finalArray[] = array_sum($subTotal[2]);
// Will print '50, 80, 120, '
foreach($finalArray as $total) {
echo $total.', ';
}
Hope this helps!

Can we include condition as an argument in custom functions?

Suppose I have a multidimensional array
$num1 = array(1, 4, 6, 12, 15, 16, 21, 34, 25, 29);
$num2 = array(1, 5, 18, 19, 23, 19, 23, 45, 23, 16);
$array = array($num1, $num2);
I want to extract all the values from $array where the $array[0] values meet some condition e.g. have a value between 10 & 20.
to get the required values from $array I can use this code:
$count = count($array[0]);
$new_array = array_fill(0, $count, array());
for($i = 0; $i < $count; $i++)
{
if($array[0][$i] >= 10 && $array[0][$i] <= 20)
{
$new_array[0][] = $array[0][$i];
$new_array[1][] = $array[1][$i];
}
}
//I get the array that I need
print_r($new_array);
This is the code I need to change every time
$array[0][$i] >= 10 && $array[0][$i] <= 20 (condition --> values from the first sub array are >= 10 and <= 20)
result would be
Array(0 => Array(0 => 12, 1 => 15, 2 => 16), 1 => Array(0 => 19, 1 => 23, 2 => 19))
another condition
$array[1][$i] >= 20 && $array[1][$i] <= 30 (condition --> values from the second sub array are >= 20 and <= 30)
result would be
Array(0 => Array(0 => 15, 1 => 21, 2 => 25), 1 => Array(0 => 23, 1 => 23, 2 => 23))
I need to do such operations with different columns using different conditions. So, instead of writing code for looping every time, I want to create a function with condition as an argument. Is it possible, if so how?
I would like to have a function with three arguments as shown below
function_name ($array, $column_num, $condition)
Any alternative solutions are also welcome.... :)
Code I used finally to get this done....
<?php
function mdarray_condition_extract($array, $column, $condition)
{
$count = count($array[0]);
$nsac = count($array);
$new_array = array_fill(0, $nsac, array());
for ($i = 0; $i < $count; $i++)
{
$valToTest = $array[$column][$i];
if ($condition($valToTest))
{
for($k = 0; $k < $nsac; $k++)
{
$new_array[$k][] = $array[$k][$i];
}
}
}
return $new_array;
}
$array = array(array(1, 4, 6, 12, 15, 16), array(1, 5, 18, 19, 23, 19));
$columns = array(0,1,0);
$conditions = [
0 => function($val){return $val >= 10 && $val <= 20;},
1 => function($val){return $val >= 20 && $val <= 30;},
2 => function($val){return $val == 6 || $val == 20;}
];
$combo = array($columns, $conditions);
$condcount = count($combo[0]);
for($i = 0; $i < $condcount; $i++)
{
print_r(mdarray_condition_extract($array, $combo[0][$i], $combo[1][$i])); echo "<br><br>";
}
?>
Thanks all for the response, it helped me in a great way...!!
Your existing code is very close.
function filterParallelArrays($array, $predicateFilterIndex, $predicate)
{
$count = count($array[0]);
$new_array = array_fill(0, $count, array());
for ($i = 0; $i < $count; $i++)
{
$valToTest = $array[$predicateFilterIndex][$i];
if ($predicate($valToTest))
{
$new_array[0][] = $array[0][$i];
$new_array[1][] = $array[1][$i];
}
}
return $new_array;
}
$predicate = function($val)
{
return $val >= 10 && $val <= 20;
};
print_r(filterParallelArrays($array, 0, $predicate));
You question is about filtering your arrays. For that, PHP has built-in function array_filter() . It takes callback for filtering values.
If I got your question correctly, you want to apply filter to your sub-arrays - and, probably, with different conditions. Normally, if do that statically, it is:
$array[0] = array_filter($array[0], function($x)
{
return $x>=10 && $x<=20; //item between 10 and 20
});
-but if you have predefined list for each column, you can fill a map:
$conditions = [
//column index => condition callback:
0 => function($x){ return $x>=10 && $x<=20; },
1 => function($x){ return $x==50 || $x==80; },
//e t.c.
];
foreach($array as $key=>$column)
{
if(array_key_exists($key, $conditions))
{
$array[$key] = array_filter($array[$key], $conditions[$key]);
}
}
So, using array_filter() - you can do it natively, I think you won't need your own custom function to do this (because wrapping native function has little sense in this case).
Given your latest update, you could do something like this. But I'm still not really sure what your objective is here, so this might be totally out to lunch.
function array_function($key, $lcond, $rcond)
{
$count = count($array[0]);
$new_array = array_fill(0, $count, array());
for($i = 0; $i < $count; $i++)
{
if($array[$key][$i] >= $lcond && $array[$key][$i] <= $rcond)
{
$new_array[0][] = $array[0][$i];
$new_array[1][] = $array[$key][$i];
}
}
//I get the array that I need
return $new_array;
}

Getting the most repeated values in an array [duplicate]

This question already has answers here:
PHP get the item in an array that has the most duplicates
(2 answers)
Closed 1 year ago.
I have an array of numbers like this:
$array = array(1,1,1,4,3,1);
How do I get the count of most repeated value?
This should work:
$count=array_count_values($array);//Counts the values in the array, returns associatve array
arsort($count);//Sort it from highest to lowest
$keys=array_keys($count);//Split the array so we can find the most occuring key
echo "The most occuring value is $keys[0][1] with $keys[0][0] occurences."
I think array_count_values function can be useful to you. Look at this manual for details : http://php.net/manual/en/function.array-count-values.php
You can count the number of occurrences of values in an array with array_count_values:
$counts = array_count_values($array);
Then just do a reverse sort on the counts:
arsort($counts);
Then check the top value to get your mode.
$mode = key($counts);
If your array contains strings or integers only you can use array_count_values and arsort:
$array = array(1, 1, 1, 4, 3, 1);
$counts = array_count_values($array);
arsort($counts);
That would leave the most used element as the first one of $counts. You can get the count amount and value afterwards.
It is important to note that if there are several elements with the same amount of occurrences in the original array I can't say for sure which one you will get. Everything depends on the implementations of array_count_values and arsort. You will need to thoroughly test this to prevent bugs afterwards if you need any particular one, don't make any assumptions.
If you need any particular one, you'd may be better off not using arsort and write the reduction loop yourself.
$array = array(1, 1, 1, 4, 3, 1);
/* Our return values, with some useless defaults */
$max = 0;
$max_item = $array[0];
$counts = array_count_values($array);
foreach ($counts as $value => $amount) {
if ($amount > $max) {
$max = $amount;
$max_item = $value;
}
}
After the foreach loop, $max_item contains the last item that appears the most in the original array as long as array_count_values returns the elements in the order they are found (which appears to be the case based on the example of the documentation). You can get the first item to appear the most in your original array by using a non-strict comparison ($amount >= $max instead of $amount > $max).
You could even get all elements tied for the maximum amount of occurrences this way:
$array = array(1, 1, 1, 4, 3, 1);
/* Our return values */
$max = 0;
$max_items = array();
$counts = array_count_values($array);
foreach ($counts as $value => $amount) {
if ($amount > $max) {
$max = $amount;
$max_items = array($value);
} elif ($amount = $max) {
$max_items[] = $value;
}
}
$vals = array_count_values($arr);
asort($vals);
//you may need this end($vals);
echo key($vals);
I cant remember if asort sorts asc or desc by default, you can see the comment in the code.
<?php
$arrrand = '$arr = array(';
for ($i = 0; $i < 100000; $i++)
{
$arrrand .= rand(0, 1000) . ',';
}
$arrrand = substr($arrrand, 0, -1);
$arrrand .= ');';
eval($arrrand);
$start1 = microtime();
$count = array_count_values($arr);
$end1 = microtime();
echo $end1 - $start1;
echo '<br>';
$start2 = microtime();
$tmparr = array();
foreach ($arr as $key => $value);
{
if (isset($tmparr[$value]))
{
$tmparr[$value]++;
} else
{
$tmparr[$value] = 1;
}
}
$end2 = microtime();
echo $end2 - $start2;
Here check both solutions:
1 by array_count_values()
and one by hand.
<?php
$input = array(1,2,2,2,8,9);
$output = array();
$maxElement = 0;
for($i=0;$i<count($input);$i++) {
$count = 0;
for ($j = 0; $j < count($input); $j++) {
if ($input[$i] == $input[$j]) {
$count++;
}
}
if($count>$maxElement){
$maxElement = $count;
$a = $input[$i];
}
}
echo $a.' -> '.$maxElement;
The output will be 2 -> 3
$arrays = array(1, 2, 2, 2, 3, 1); // sample array
$count=array_count_values($arrays); // getting repeated value with count
asort($count); // sorting array
$key=key($count);
echo $arrays[$key]; // get most repeated value from array
String S;
Scanner in = new Scanner(System.in);
System.out.println("Enter the String: ");
S = in.nextLine();
int count =1;
int max = 1;
char maxChar=S.charAt(0);
for(int i=1; i <S.length(); i++)
{
count = S.charAt(i) == S.charAt(i - 1) ? (count + 1):1;
if(count > max)
{
max = count;
maxChar = S.charAt(i);
}
}
System.out.println("Longest run: "+max+", for the character "+maxChar);
here is the solution
class TestClass {
public $keyVal;
public $keyPlace = 0;
//put your code here
public function maxused_num($array) {
$temp = array();
$tempval = array();
$r = 0;
for ($i = 0; $i <= count($array) - 1; $i++) {
$r = 0;
for ($j = 0; $j <= count($array) - 1; $j++) {
if ($array[$i] == $array[$j]) {
$r = $r + 1;
}
}
$tempval[$i] = $r;
$temp[$i] = $array[$i];
}
//fetch max value
$max = 0;
for ($i = 0; $i <= count($tempval) - 1; $i++) {
if ($tempval[$i] > $max) {
$max = $tempval[$i];
}
}
//get value
for ($i = 0; $i <= count($tempval) - 1; $i++) {
if ($tempval[$i] == $max) {
$this->keyVal = $tempval[$i];
$this->keyPlace = $i;
break;
}
}
// 1.place holder on array $this->keyPlace;
// 2.number of reapeats $this->keyVal;
return $array[$this->keyPlace];
}
}
$catch = new TestClass();
$array = array(1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 1, 2, 3, 1, 1, 2, 5, 7, 1, 9, 0, 11, 22, 1, 1, 22, 22, 35, 66, 1, 1, 1);
echo $catch->maxused_num($array);

Categories