How to run array_filter recursively in a PHP array?
This function effectively applies filter_recursive with a provided callback
class Arr {
public static function filter_recursive($array, $callback = NULL)
{
foreach ($array as $index => $value)
{
if (is_array($value))
{
$array[$index] = Arr::filter_recursive($value, $callback);
}
else
{
$array[$index] = call_user_func($callback, $value);
}
if ( ! $array[$index])
{
unset($array[$index]);
}
}
return $array;
}
}
And you'd use it this way:
Arr::filter_recursive($my_array, $my_callback);
This might help someone
From the PHP array_filter
documentation:
//This function filters an array and remove all null values recursively.
<?php
function array_filter_recursive($input)
{
foreach ($input as &$value)
{
if (is_array($value))
{
$value = array_filter_recursive($value);
}
}
return array_filter($input);
}
?>
//Or with callback parameter (not tested) :
<?php
function array_filter_recursive($input, $callback = null)
{
foreach ($input as &$value)
{
if (is_array($value))
{
$value = array_filter_recursive($value, $callback);
}
}
return array_filter($input, $callback);
}
?>
Should work
$count = array_sum(array_map(function ($item) {
return ((int) !is_null($item['pts_m'])
+ ((int) !is_null($item['pts_mreg'])
+ ((int) !is_null($item['pts_cg']);
}, $array);
or maybe
$count = array_sum(array_map(function ($item) {
return array_sum(array_map('is_int', $item));
}, $array);
There are definitely many more possible solutions. If you want to use array_filter()
(without callback) remember, that it treats 0
as false
too and therefore it will remove any 0
-value from the array.
If you are using PHP in a pre-5.3 version, I would use a foreach
-loop
$count = 0;
foreach ($array as $item) {
$count += ((int) !is_null($item['pts_m'])
+ ((int) !is_null($item['pts_mreg'])
+ ((int) !is_null($item['pts_cg']);
}
Update
Regarding the comment below:
Thx @kc I actually want the method to remove false, 0, empty etc
When this is really only, what you want, the solution is very simple too. But now I don't know, how to interpret
My expected result here would be 5.
Anyway, its short now :)
$result = array_map('array_filter', $array);
$count = array_map('count', $result);
$countSum = array_sum($count);
The resulting array looks like
Array
(
[147] => Array
(
[pts_mreg] => 1
[pts_cg] => 1
)
[158] => Array
(
)
[159] => Array
(
[pts_mreg] => 1
[pts_cg] => 1
)
)
A better alternative
One implementation that always worked for me is this one:
function filter_me(&$array) {
foreach ( $array as $key => $item ) {
is_array ( $item ) && $array [$key] = filter_me ( $item );
if (empty ( $array [$key] ))
unset ( $array [$key] );
}
return $array;
}
I notice that someone had created a similar function except that this one presents, in my opinion, few advantages:
- you pass an array as reference (not its copy) and thus the algorithm is memory-friendly
- no additional calls to array_filter which in reality involves:
- the use of stack, ie. additional memory
- some other operations, ie. CPU cycles
Benchmarks
- A 64MB array
- filter_me function finished in 0.8s AND the PHP allocated memory before starting the function was 65MB, when function returned it was 39.35MB !!!
- array_filter_recursive function recommended above by Francois Deschenes had no chance; after 1s PHP Fatal error: Allowed memory size of 134217728 bytes exhausted
- A 36MB array
- filter_me function finished in 0.4s AND the PHP allocated memory before starting the function was 36.8MB, when function returned it was 15MB !!!
- array_filter_recursive function succeeded this time in 0.6s and memory before/after was quite the same
I hope it helps.