Recursively deleting elements from an array
I had a need recently to delete items from a nested associative array and also any empty sub-arrays. My initial thought was to use array_walk_recursive, but this doesn’t work as you can’t unset nested elements and you only have access to the leaves. Clearly I needed a recursive function.
I’m sure that this has been done many times before, but this is my solution:
/** * Remove any elements where the callback returns true * * @param array $array the array to walk * @param callable $callback callback takes ($value, $key, $userdata) * @param mixed $userdata additional data passed to the callback. * @return array */ function array_walk_recursive_delete(array &$array, callable $callback, $userdata = null) { foreach ($array as $key => &$value) { if (is_array($value)) { $value = array_walk_recursive_delete($value, $callback, $userdata); } if ($callback($value, $key, $userdata)) { unset($array[$key]); } } return $array; }
with this test:
class FunctionsTest extends \PHPUnit_Framework_TestCase { public function testArrayWalkRecursiveDelete() { $array = [ 'a'=> 'a', 'b'=> null, 'c' => [ 'a' => null, 'b' => 'b', ], 'd' => [ 'a' => null ] ]; $result = array_walk_recursive_delete($array, function ($value, $key) { if (is_array($value)) { return empty($value); } return ($value === null); }); $expected = [ 'a'=> 'a', 'c' => [ 'b' => 'b', ], ]; $this->assertSame($expected, $result); } }
This is very similar to how array_walk_recursive works except that I return the altered array rather than a boolean as it’s a recursive function.
The test shows how I use it:
$result = array_walk_recursive_delete($array, function ($value, $key) { if (is_array($value)) { return empty($value); } return ($value === null); });
If the callback returns true, then the element is deleted from the array, so for my case, I return true if the value is an empty array or null.
Something like this should do the trick too
https://gist.github.com/david4worx/1a991a705a52d8f9b16b
Ps; you forgot the 3rd param in your docblocks of the function.
Thanks David. I've updated the docblock.