Can we include condition as an argument in custom functions? - php

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;
}

Related

Iteration over sorted associative array

I have array with positive int values like [4, 1, 75, 52, 5, 24]. I need to find two values with minimal difference. Also, I need the original keys of those two. So, I sorted the array with asort() to keep the keys. Now when I iterate I have a problem - I can't use $key + 1 to point to next element and using next() and prev() makes it difficult to get the keys (once you use next or prev pointer is moved):
for ($i = 0; $i < count($sorted)-1; $i++) {
if (current($sorted) - next($sorted) < $min) {
//echo prev($sorted) - next($sorted) . '<br>';
}
}
What would you do?
(Feel free to alter array in any other form if that makes this easier - asort is not necessary)
If I need to explain one more time: I have a problem with keys. Finding the closest values is not a problem.
I completely revamped your snippet. You can take whatever you want from below snippet,
$array = [4, 1, 5, 52, 75, 52, 24];
function difference($arr)
{
$n = count($arr);
// Initialize difference
// as infinite
$diff = PHP_INT_MAX;
// Find the min diff by comparing
// difference of all possible
// pairs in given array
$two_values = [];
for ($i = 0; $i < $n - 1; $i++) {
for ($j = $i + 1; $j < $n; $j++) {
if (abs($arr[$i] - $arr[$j]) < $diff) {
$diff = abs($arr[$i] - $arr[$j]);
$two_values['values'] = [$arr[$i], $arr[$j]];
$two_values['keys'] = [$i, $j];
$two_values['diff'] = $diff;
}
}
}
// Return min diff
return $two_values;
}
print_r(difference($array));
Demo.
Please let me know if something is not getting.
I found my own way to do this using additional array with keys and array_multisort()
$numbers = [4, 1, 75, 1, 52, 5, 52, 24, 52];
$ar = [];
$mins = [];
$min = PHP_INT_MAX;
foreach ($numbers as $key => $number) {
$ar[] = ['key' => $key, 'number' => $number];
}
array_multisort(array_column($ar, 'number'), SORT_DESC, array_column($ar, 'key'), SORT_DESC, $ar );
foreach ($ar as $key => $value) {
if (!isset($ar[$key + 1])) break;
if ($value['number'] - $ar[$key + 1]['number'] <= $min) {
$min = $value['number'] - $ar[$key + 1]['number'];
$mins = [$ar[$key + 1], $ar[$key]];
}
}

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>

best way to count the bigger elements on the right and left side of an array

For example, in php
$arr = [9, 4, 3, 5, 2, 6];
then,
$output = [[0,0], [1,2], [2,2], [1,1], [4,1], [1,0]];
[0, 0] = the bigger elements of 9 is 0 on both side
[1, 2] = the bigger elements of 4 is 1 (9) on left and 2 (5, 6) on right side ... [ 9 > 4] - [ 5 > 4, 6 > 4 ]
[2, 2] = the bigger elements of 3 is 2 (9, 4) on the left and 2 (5, 6) on right side
[1, 1] = the bigger elements of 5 is 1 (9) on the left and 1 (6) on the right side
[4, 1] = the bigger elements of 2 (9, 4, 3, 5) is 4 on the left and 1 (6) on the right side
[1, 0] = the bigger elements of 6 is 1 (9) on the left and 0 (no elements after 6) on the right side
I want it in O(n log(n)), is it possible?
Looks like lots of answers already, you could do this with some of the array functions like some of the answers did, but since this is probably for your homework best to keep it simple. I keep track of whether it's left or right that should be incremented each iteration by using the $side variable.
$arr = [9, 4, 3, 5, 2, 6];
$results = [];
for ($x = 0; $x < count($arr); $x++) {
$results[$x] = [0,0];
$side = 0;
for ($y = 0; $y < count($arr); $y++) {
if ($arr[$y] > $arr[$x]) {
$results[$x][$side]++;
} elseif ($arr[$x] == $arr[$y]) {
$side = 1;
}
}
}
You need to loop through $arr to get each value, and then, in the loop, loop again through $arr to get the other values. Then, in the second loop, you build your output array by comparing both the value (to know if the number is, indeed, bigger) and the key (to know if it's on the left or the right).
$arr = array(9, 4, 3, 5, 2, 6);
$output = array();
foreach ($arr as $key=>$value) {
$out = array(0, 0);
foreach ($arr as $key2=>$value2) {
if ($key2 == $key) # If it's the same element
continue;
if ($value2 > $value) {
if ($key2 < $key)
$out[0]++;
else
$out[1]++;
}
}
$output[] = $out;
}
print_r($output);
See the output here.
Try this:
function fix_array($array) {
$return_array = array();
foreach ($array as $i => $value){
$left = array_slice($array, 0, $i);
$count_left = count(array_filter($left, function($var) use($value){
return $var > $value;
}));
$right = array_slice($array, $i + 1);
$count_right = count(array_filter($right, function($var) use($value){
return $var > $value;
}));
$return_array[] = [$count_left, $count_right];
}
return $return_array;
}
$arr = [9, 4, 3, 5, 2, 6];
$new_array = fix_array($arr);
print_r($new_array);
Simply compare it with left and right values. Try this:
$arr = [9, 4, 3, 5, 2, 6];
$total = count($arr);
$new_arr=array();
foreach ($arr as $key => $value) {
$left = 0;
$right = 0;
for ($i=0; $i < $total; $i++) {
if($key > $i && $arr[$i] > $arr[$key])
{
$left++;
}
elseif ($key < $i && $arr[$i] > $arr[$key]) {
$right++;
}
}
$new_arr[]=[$left,$right];
}
echo "<pre>";
print_r($new_arr);
Try the following code using array_walk()
<?php
$arr = [9, 4, 3, 5, 2, 6];
$finalArray =[];
array_walk($arr, function($value,$key) use(&$finalArray,&$arr) {
$param ['pre_val']=0;
$param ['post_val']=0;
$param ['current_index'] = $key;
$param ['current_value'] = $value;
$arr2 = $arr;
array_walk($arr2, function(&$value,$key) use(&$finalArray,&$param) {
if($key < $param['current_index']){
if($value > $param['current_value']){$param['pre_val'] ++;}
}else{
if($value > $param['current_value']){$param['post_val'] ++;}
}
$finalArray[$param['current_index']][0] = $param['pre_val'];
$finalArray[$param['current_index']][1] = $param['post_val'];
});
});
print_r($finalArray);

Cumulative array

I have this array:
$a = array(1, 2, 3, 4, 5, 7, 8, 10, 12);
Is there a function to convert this to:
$b = array(1, 1, 1, 1, 2, 1, 2, 2);
So basicaly:
$b = array ($a[1]-$a[0], $a[2]-$a[1], $a[3]-$a[2], ... ,$a[n]-$a[n-1]);
Here is the code I have so far:
$a = $c = array(1, 2, 3, 4, 5, 7, 8, 10, 12);
array_shift($c);
$d = array();
foreach ($a as $key => $value){
$d[$key] = $c[$key]-$value;
}
array_pop($d);
There isn't a built-in function that can do this for you, but you could turn your code into one instead. Also, rather than making a second array, $c, you could use a regular for loop to loop through the values:
function cumulate($array = array()) {
// re-index the array for guaranteed-success with the for-loop
$array = array_values($array);
$cumulated = array();
$count = count($array);
if ($count == 1) {
// there is only a single element in the array; no need to loop through it
return $array;
} else {
// iterate through each element (starting with the second) and subtract
// the prior-element's value from the current
for ($i = 1; $i < $count; $i++) {
$cumulated[] = $array[$i] - $array[$i - 1];
}
}
return $cumulated;
}
I think php has not a build in function for this. There are many ways to solve this, but you already wrote the answer:
$len = count($a);
$b = array();
for ($i = 0; $i < $len - 1; $i++) {
$b[] = $a[$i+1] - $a[$i];
}

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