PHP - using a recursive function to find the max() of nested arrays - php

The following code uses a simple strategy for finding the max of the nested array. It uses foreach to find and label the max value, however, if I got an array that was nested to MORE than two levels, than my code would be useless. Can anyone please explain to me the idea of a function calling itself for it to find unlimited nested arrays? Would be much appreciated.
Here is my code for example:
<?php
$arr = array("1", "2", array("3", "4"));
foreach($arr as $value){
if(is_array($value)){
foreach($value as $value2){
$max_array=array($value);
// no deeper levels
}
} else {
$max_array=array($value);
}
}
echo max($max_array);
?>

You can use array_walk_recursive() for it:
function array_max_recursive($arr)
{
$max = -INF;
array_walk_recursive($arr, function($item) use (&$max) {
if ($item > $max) {
$max = $item;
}
});
return $max;
}
echo array_max_recursive(["1", "2", ["3", "4"]]); // 4

What you want is a recursive function.
The function looks up the biggest element in a an array. If an item in the array is an array, it will find the biggest item in that array and use that to compare.
To find the biggest value in that array it will use the same function.
function findMax($arr){
$max = 0;
foreach($arr as $item){
if(is_array($item)){
$val = findMax($item);
}else{
$val = $item;
}
$max = $val>$max?$val:$max;
}
return $max;
}
Use example:
$arr = Array(1,2,Array(3,10,Array(6,7)));
$arr2 = Array(1,2,Array(3,5,Array(6,7)));
echo findMax($arr)."\n".findMax($arr2);
Result:
10
7

Related

Search in Multidimensional Array in PHP

$data = array
(
array("Ravi","Kuwait",350),
array("Sameer","UK",400),
array("Aditi","Switzerland",50),
array("Akshay","India",250),
array("rishi","Singapore",200),
array("Mukul","Ireland",100)
);
I want to put condition to the third row such that I can get entries of less than 300.
I suppose that you meant "the third element" in each nested array.Use array_filter function to get an array of elements, those third element's value is less than 300:
$result = array_filter($data, function($v) { return $v[2] < 300; });
print_r($result);
Try this code:
<?php
$data = array
(
array("Ravi","Kuwait",350),
array("Sameer","UK",400),
array("Aditi","Switzerland",50),
array("Akshay","India",250),
array("rishi","Singapore",200),
array("Mukul","Ireland",100)
);
$newArray = array();
foreach($data as $key => $value)
{
if($value[2] <= 100)
$newArray[] = $value;
}
print_r($newArray);
?>
You can achieve this using the PHP function array_filter() :
PHP
function limitArray($array) {
return ($array[2] <= 300);
}
print_r(array_filter($data, 'limitArray'));
evalIN

Count keys in array

I've written the below function, it takes in a 2 dimensional array and return the number of times a key occurs, BUT it feels like i may be reinventing the wheel here, is there an easy way?
function countKeys($array, $key)
{
$results = array();
foreach($array as $row)
{
if (array_key_exists($row[$key], $results))
{
$results[$row[$key]] += 1;
}
else
{
$results[$row[$key]] = 1;
}
}
return $results;
}
To count the keys in a two dimensional array with a search I would do this -
function countKeys($array,$search){
$key_count = array(); // new array
foreach($array as $record) {
$keys = array_keys($record);
foreach($keys as $key){
if($key == $search){ // check against the search term
array_push($key_count, $key); // add the key to the new array
}
}
}
return count($key_count); // just count the new array
}
echo countKeys($records, 'last_name');
EXAMPLE
array_keys()
count()
For a 2 dimensional array try:
$result = count(array_column($array, $key));
PHP >= 5.5.0 needed for array_column() or use the PHP Implementation of array_column()
Just use count() function like:
count($array);
see: http://php.net/manual/pt_BR/function.count.php
You can use this function to count arrays variable as well.
Hope it helps you.

How to select and loop through only items that meet certain conditions in array

I want to loop through an array with a comparison operator being applied.
So, whereas this code:
$arr = array(1,2,3,4,5,6,7,8,9);
foreach($arr as $key)
{
echo $key;
}
will echo "123456789," I want a code that could only list numbers greater than 5, or less than 5, etc. (So it would output 6789 or 1234.)
Note: I'm nearly sure there is a way to do this, and it is relatively simple, but I can't find a way to do it, and there appears to be no question asking this on stackoverflow. I have looked, but as my title shows, I'm not sure how to succinctly state this for googleing. Thank you.
Note: I had considered using an external condition check, but I guessed if there was a php function specifically for this, it would be more efficient.
UPDATE: array_filter was suggested, so I ran the following benchmark, to test whether the traditional or built-in approach was better here:
$arr=array();
for($x=1;$x<10001;$x++){
$arr[]=$x;
}
$a1 = microtime();
foreach($arr as $key) {
if ($key > 5000) {
echo $key;
}
}
$a2 = microtime();
$a3 = microtime();
$greater = array_filter($arr, function ($key) {
return $key > 5000;
});
foreach($greater as $key) {
echo $key;
}
$a4 = microtime();
$firsttest=$a2-$a1;
$secondtest=$a4-$a3;
echo '<br>'.$firsttest.'<br>'.$secondtest;
The second test took about twice to three times as long consistently, meaning using foreach and then using an if condition is far more efficient than using array_filter and then using a foreach loop.
You can just add a condition around the echo.
$arr = array(1,2,3,4,5,6,7,8,9);
foreach($arr as $key) {
if ($key > 5) {
echo $key;
}
}
Or use a ternary operator, echoing an empty string if it's not greater than five.
$arr = array(1,2,3,4,5,6,7,8,9);
foreach($arr as $key) {
echo $key > 5 ? $key : '';
}
And then there's array_filter which would allow you to extract all the values > 5 and put them in their own array. It's useful if you need to keep those values around for later.
$arr = array(1,2,3,4,5,6,7,8,9);
$greater = array_filter($arr, function($key) {
return $key > 5;
});
foreach($greater as $key) {
echo $key;
}
$arr = array(1,2,3,4,5,6,7,8,9);
foreach($arr as $key)
{
if($key > 5)
echo $key;
}

Knowning at which point we are in a foreach

I have an array:
$array=array('key1'=>'value1','key2'=>'value2','value3');
and a foreach:
foreach($array as $v){
//do something
}
Is there a way to know in the foreach which element we are parsing?
(without doing something like:)
$count=0;
foreach($array as $v){
$count++;
// do something
}
thanks
EDIT1:
Sorry maybe I was not clear:
I don't want know the key, but I need to know how many elements are left in the foreach. (that's why I did the example with $count)
You could use a class that extends ArrayIterator:
class FooArrayIterator extends ArrayIterator {
private $offset = 0;
public function next() {
$this->offset++;
return parent::next();
}
public function rewind() {
$this->offset = 0;
parent::rewind();
}
public function seek($offset) {
if ($offset >= 0 && $offset < $this->count()) {
$this->offset = $offset;
}
parent::seek($offset);
}
public function offset() {
return $this->offset;
}
}
Example:
$array = array('value1','value2','value3');
$iter = new FooArrayIterator($array);
foreach ($iter as $v) {
echo ($iter->count() - $iter->offset() - 1).' more';
}
You can get the actual index:
foreach ($array as $index => $value) {
}
If you are working with an associative array there is no way to tell the current position of the internal array pointer. There is only an indirect way: you search for the current key in the keys of the array with:
foreach ($array as $index => $value) {
$position = array_search ($index, array_keys ($array));
echo ($position);
}
... but I guess count++ is a much more resource-friendly way.
You can:
$count = count($array);
foreach($array as $key => $value) {
$count--;
//$count elements are left
}
Yes, sort of.
foreach($array as $key=>$value)
// code
}
$key will be the array key, although if you want an actual integer count of iterations, and the keys are not numbered sequentially, or are strings, you will have to use a counter like in your original post.
Edit: to handle the last element without implementing a counter, you can use (if keys are int)
$foo = ($key == count($array)-1) ? "last element" : "any other element";
(janked from the manual comments - http://php.net/manual/en/control-structures.foreach.php)
Edit: if your keys are not integers, you can create a counter like you have in your code above, and substitute $key with your counter variable.
You're being a bit too picky :)
By the way the trick is to transform an associative array to an indexed array:
foreach ( array_values($array) as $key=>$value ){
echo $key; //yes, it will be an INT
echo ( count($array) - $key );
}
Without some pre-processing, such as your count() version, there isn't any way to know where you are in an associative array. At most you can check if you're at the end with end(), but there's no guarantee as to what order foreach() will retrieve the individual elements. Generally it's the same order they got added to the array, but not guarantees.
Another pre-processing option would be
$keys = array_keys($array);
$cnt = count($keys)
for ($i = 0; $i < $cnt; $i++) {
$element = $array[$keys[$i]];
}
and $i would tell you exactly how far through you've gone.

Removing array item by value [duplicate]

This question already has answers here:
PHP: How to remove specific element from an array?
(22 answers)
PHP array delete by value (not key)
(20 answers)
Closed 1 year ago.
I need to remove array item with given value:
if (in_array($id, $items)) {
$items = array_flip($items);
unset($items[ $id ]);
$items = array_flip($items);
}
Could it be done in shorter (more efficient) way?
It can be accomplished with a simple one-liner.
Having this array:
$arr = array('nice_item', 'remove_me', 'another_liked_item', 'remove_me_also');
You can do:
$arr = array_diff($arr, array('remove_me', 'remove_me_also'));
And the value of $arr will be:
array('nice_item', 'another_liked_item')
I am adding a second answer. I wrote a quick benchmarking script to try various methods here.
$arr = array(0 => 123456);
for($i = 1; $i < 500000; $i++) {
$arr[$i] = rand(0,PHP_INT_MAX);
}
shuffle($arr);
$arr2 = $arr;
$arr3 = $arr;
/**
* Method 1 - array_search()
*/
$start = microtime(true);
while(($key = array_search(123456,$arr)) !== false) {
unset($arr[$key]);
}
echo count($arr). ' left, in '.(microtime(true) - $start).' seconds<BR>';
/**
* Method 2 - basic loop
*/
$start = microtime(true);
foreach($arr2 as $k => $v) {
if ($v == 123456) {
unset($arr2[$k]);
}
}
echo count($arr2). 'left, in '.(microtime(true) - $start).' seconds<BR>';
/**
* Method 3 - array_keys() with search parameter
*/
$start = microtime(true);
$keys = array_keys($arr3,123456);
foreach($keys as $k) {
unset($arr3[$k]);
}
echo count($arr3). 'left, in '.(microtime(true) - $start).' seconds<BR>';
The third method, array_keys() with the optional search parameter specified, seems to be by far the best method. Output example:
499999 left, in 0.090957164764404 seconds
499999left, in 0.43156313896179 seconds
499999left, in 0.028877019882202 seconds
Judging by this, the solution I would use then would be:
$keysToRemove = array_keys($items,$id);
foreach($keysToRemove as $k) {
unset($items[$k]);
}
How about:
if (($key = array_search($id, $items)) !== false) unset($items[$key]);
or for multiple values:
while(($key = array_search($id, $items)) !== false) {
unset($items[$key]);
}
This would prevent key loss as well, which is a side effect of array_flip().
to remove $rm_val from $arr
unset($arr[array_search($rm_val, $arr)]);
The most powerful solution would be using array_filter, which allows you to define your own filtering function.
But some might say it's a bit overkill, in your situation...
A simple foreach loop to go trough the array and remove the item you don't want should be enough.
Something like this, in your case, should probably do the trick :
foreach ($items as $key => $value) {
if ($value == $id) {
unset($items[$key]);
// If you know you only have one line to remove, you can decomment the next line, to stop looping
//break;
}
}
Try array_search()
Your solutions only work if you have unique values in your array
See:
<?php
$trans = array("a" => 1, "b" => 1, "c" => 2);
$trans = array_flip($trans);
print_r($trans);
?>
A better way would be unset with array_search, in a loop if neccessary.
w/o flip:
<?php
foreach ($items as $key => $value) {
if ($id === $value) {
unset($items[$key]);
}
}
function deleteValyeFromArray($array,$value)
{
foreach($array as $key=>$val)
{
if($val == $value)
{
unset($array[$key]);
}
}
return $array;
}
You can use array_splice function for this operation Ref : array_splice
array_splice($array, array_search(58, $array ), 1);

Categories