How to run array_filter recursively in a PHP array?

前端 未结 6 1792
挽巷
挽巷 2020-11-29 11:16

Given the following array $mm

Array
(
    [147] => Array
        (
            [pts_m] => 
            [pts_mreg] => 1
            [pts         


        
相关标签:
6条回答
  • 2020-11-29 12:06

    I needed an array filter recursive function that would walk through all nodes (including arrays, so that we have the possibility to discard entire arrays), and so I came up with this:

    
        public static function filterRecursive(array $array, callable $callback): array
        {
            foreach ($array as $k => $v) {
                $res = call_user_func($callback, $v);
                if (false === $res) {
                    unset($array[$k]);
                } else {
                    if (is_array($v)) {
                        $array[$k] = self::filterRecursive($v, $callback);
                    }
                }
            }
    
            return $array;
        }
    

    See more examples here: https://github.com/lingtalfi/Bat/blob/master/ArrayTool.md#filterrecursive

    0 讨论(0)
  • 2020-11-29 12:12

    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

    0 讨论(0)
  • 2020-11-29 12:14
    <?php
    
    $mm = array
    (
        147 => array
            (
                "pts_m" => "",
                "pts_mreg" => 1,
                "pts_cg" => 1
            ) ,
        158 => array
            (
                "pts_m" => null ,
                "pts_mreg" => null,
                "pts_cg" => 0
            ),
    
        159 => array
            (
                "pts_m" => "",
                "pts_mreg" => 1,
                "pts_cg" => 1
            )
    
    );
    
    $count = 0;
    foreach ($mm as $m) {
        foreach ($m as $value) {
            if($value !== false && $value !== "" && $value !== null) {
                $count++;
            }
        }
    }
    echo $count;
    ?>
    
    0 讨论(0)
  • 2020-11-29 12:18

    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
        )
    
    )
    
    0 讨论(0)
  • 2020-11-29 12:19

    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:

    1. you pass an array as reference (not its copy) and thus the algorithm is memory-friendly
    2. no additional calls to array_filter which in reality involves:
      • the use of stack, ie. additional memory
      • some other operations, ie. CPU cycles

    Benchmarks

    1. 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
    2. 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.

    0 讨论(0)
  • 2020-11-29 12:21

    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); 
      } 
    ?>
    
    0 讨论(0)
提交回复
热议问题