Как запустить фильтр массива рекурсивно в массиве PHP?

учитывая следующий массив $mm

Array
(
    [147] => Array
        (
            [pts_m] => 
            [pts_mreg] => 1
            [pts_cg] => 1
        )    
    [158] => Array
        (
            [pts_m] => 
            [pts_mreg] => 
            [pts_cg] => 0
        )

    [159] => Array
        (
            [pts_m] => 
            [pts_mreg] => 1
            [pts_cg] => 1
        )

)

когда я запускаю count(array_filter($mm)) Я 3 как результат, так как он не рекурсивен.

count(array_filter($mm), COUNT_RECURSIVE) также не будет делать, потому что мне действительно нужно запустить array_filter рекурсивно, а затем подсчитать его результат.

Итак, мой вопрос: как мне рекурсивно запустить array_filter($mm) в этом случае? Мой ожидаемый результат здесь будет 4.

обратите внимание, что я не использую обратный вызов, поэтому я могу исключить false, null и пустой.

5 ответов


должно работать

$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);

или, может быть,

$count = array_sum(array_map(function ($item) {
  return array_sum(array_map('is_int', $item));
}, $array);

есть, безусловно, еще много возможных решений. Если вы хотите использовать array_filter() (без обратного вызова) помните, что он лечит 0 as false и поэтому удалить любой 0-значение из массива.

если вы используете PHP в версии pre-5.3, я бы использовал 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']);
}

обновление

по поводу комментария ниже:

Thx @kc я действительно хочу, чтобы метод удалил false, 0, empty etc

когда это действительно только то, что вы хотите, решение тоже очень простое. Но теперь я не знаю, как истолковать

мой ожидаемый результат здесь будет 5.

во всяком случае, его короткие теперь :)

$result = array_map('array_filter', $array);
$count = array_map('count', $result);
$countSum = array_sum($count);

результирующий массив выглядит так:

Array
(
[147] => Array
    (
        [pts_mreg] => 1
        [pts_cg] => 1
    )    
[158] => Array
    (
    )

[159] => Array
    (
        [pts_mreg] => 1
        [pts_cg] => 1
    )

)

С PHP array_filter документация:

//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); 
  } 
?>

лучшая альтернатива

одна реализация, которая всегда работала для меня, это:

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;
}

Я замечаю, что кто-то создал аналогичную функцию, за исключением того, что эта представляет, на мой взгляд, несколько преимуществ:

  1. вы передаете массив в качестве ссылки (а не его копию), и, таким образом, алгоритм удобен для памяти
  2. никаких дополнительных вызовов array_filter, который на самом деле включает:
    • использование стека, то есть. дополнительная память
    • некоторые другие операции, т. е.. CPU cycles

критерии

  1. размером 64Мб массива
    • filter_me функция закончена в 0.8 s и выделенная PHP память перед запуском функции была 65MB, когда функция вернулась, это было 39.35 MB !!!
    • array_filter_recursive

эта функция эффективно применяет filter_recursive с предоставленным обратным вызовом

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;
    }

}

и вы бы использовали его таким образом:

Arr::filter_recursive($my_array, $my_callback);

Это может помочь кому-то


<?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;
?>