Search code examples
phparraysfilteringzeroarray-filter

Remove/Filter rows from array which contain a zero


I have an array of non-empty arrays which contain non-negative integers and I need to remove all rows/subarrays which contain at least one zero.

I know I can use a foreach() or array_filter() to make iterated calls of in_array(), but is there a more elegant/concise approach -- perhaps a functional approach without an anonymous callback?

foreach ($array as $k => $row) {
    if (in_array(0, $row)) {
        unset($array[$k]);
    }
}

Or

array_filter(
    $array,
    function($row) {
        return !in_array(0, $row);
    }
)

Sample array:

$array = [
    'one' => [20,0,40,0,60],
    'two' => [50],
    'three' => [0, 0, 0, 0],
    'four' => [10, 5],
    'five' => [0],
];

Desired output:

['two' => [50], 'four' => [10, 5]]

Solution

  • In all honesty, I think that PHP7.4's arrow function syntax makes the array_filter() call reasonably concise.

    array_filter($array, fn($row) => !in_array(0, $row))
    

    Additionally, iterated calls of !in_array() with a true third parameter can distinguish between different types and ensure that only integer-typed zeros are targeted. (Demo)

    array_filter($array, fn($row) => !in_array(0, $row, true))
    

    That said, because you have non-empty subarrays, you can use array_product as the callback name. By multiplying all values in a respective row together, any row containing a zero will result in 0. Since 0 is a falsey value, array_filter() will exclude the row from the result array. This approach will work even if there are floats or negative numbers in the subarrays. Be aware that array_product() will not remove empty rows/subarrays.

    Code: (Demo)

    var_export(
        array_filter($array, 'array_product')
    );
    

    Output:

    array (
      'two' => 
      array (
        0 => 50,
      ),
      'four' => 
      array (
        0 => 10,
        1 => 5,
      ),
    )
    

    For the slightly altered behavior of only keeping rows that contain at least one non-zero value, array_sum can be used in the same fashion. This approach will still work with empty subarrays or subarrays containing floats, but should not be trusted if a mix of negative and positive values in a respective subarray is possible. (Demo)

    var_export(
        array_filter($array, 'array_sum')
    );
    

    Output:

    array (
      'one' => 
      array (
        0 => 20,
        1 => 0,
        2 => 40,
        3 => 0,
        4 => 60,
      ),
      'two' => 
      array (
        0 => 50,
      ),
      'four' => 
      array (
        0 => 10,
        1 => 5,
      ),
    )