Рекурсивно удалять пустые элементы и подмассивы из многомерного массива - PullRequest
17 голосов
/ 27 марта 2012

Кажется, я не могу найти простого, прямого решения старой проблемы удаления пустых элементов из массивов в PHP.

Мой входной массив может выглядеть так:

Array ( [0] => Array ( [Name] => [EmailAddress] => ) ) 

(И так далее, если есть больше данных, хотя их может и не быть ...)

Если это выглядит как выше, я хочу, чтобы оно было полностью пустым после того, как я его обработал.

Итак, print_r($array); выведет:

Array ( )

Если я запускаю $arrayX = array_filter($arrayX);, я все равно получаю такой же print_r вывод. Однако везде, где я смотрел, это самый простой способ удаления пустых элементов массива в PHP5.

Я также пытался $arrayX = array_filter($arrayX,'empty_array');, но получил следующую ошибку:

Предупреждение: array_filter () [function.array-filter]: второй аргумент 'empty_array' должен быть допустимым обратным вызовом

Что я делаю не так?

Ответы [ 6 ]

26 голосов
/ 27 марта 2012

Попробуйте использовать array_map(), чтобы применить фильтр к каждому массиву в $array:

$array = array_map('array_filter', $array);
$array = array_filter($array);

Демо: http://codepad.org/xfXEeApj

5 голосов
/ 16 января 2015

Принятый ответ не делает в точности то, что спросил ОП.Если вы хотите рекурсивно удалить ВСЕ значения, которые оцениваются как ложные, включая пустые массивы, используйте следующую функцию:

function array_trim($input) {
    return is_array($input) ? array_filter($input, 
        function (& $value) { return $value = array_trim($value); }
    ) : $input;
}

Или вы можете изменить условие возврата в соответствии с вашими потребностями, например:

{ return !is_array($value) or $value = array_trim($value); }

Если вы хотите удалить только пустые массивы.Или вы можете изменить условие так, чтобы оно проверялось только на "" или на ложь или на ноль и т. Д.

5 голосов
/ 27 марта 2012

Есть множество примеров того, как это сделать. Вы можете попробовать документы , например (см. Первый комментарий).

function array_filter_recursive($array, $callback = null) {
    foreach ($array as $key => & $value) {
        if (is_array($value)) {
            $value = array_filter_recursive($value, $callback);
        }
        else {
            if ( ! is_null($callback)) {
                if ( ! $callback($value)) {
                    unset($array[$key]);
                }
            }
            else {
                if ( ! (bool) $value) {
                    unset($array[$key]);
                }
            }
        }
    }
    unset($value);

    return $array;
}

Конечно, этот пример на самом деле не использует array_filter, но вы получите точку.

3 голосов
/ 24 января 2014

Следуя предложению Джеремихарриса, мне нужно было изменить его, чтобы он заработал:

function array_filter_recursive($array) {
   foreach ($array as $key => &$value) {
      if (empty($value)) {
         unset($array[$key]);
      }
      else {
         if (is_array($value)) {
            $value = array_filter_recursive($value);
            if (empty($value)) {
               unset($array[$key]);
            }
         }
      }
   }

   return $array;
}
1 голос
/ 17 октября 2017

array_filter() по умолчанию не зависит от типа.Это означает, что любые значения zero-ish , false-y, null, empty будут удалены.Мои ссылки, чтобы следовать, продемонстрируют эту точку.

Пример входного массива OP является двумерным.Если структура данных является статической, то рекурсия не требуется.Для тех, кто хотел бы фильтровать значения нулевой длины из многомерного массива, я предоставлю статический 2-мерный метод и рекурсивный метод.

Статический 2-мерный массив : Этот код выполняет «нулевой безопасный» фильтр для элементов 2-го уровня, а затем удаляет пустые подмассивы: ( См. Эту демонстрацию, чтобы увидеть, как этот метод работает с различными (более сложными) данными массива )

$array=[
    ['Name'=>'','EmailAddress'=>'']
];   

var_export(
    array_filter(  // remove the 2nd level in the event that all subarray elements are removed
        array_map(  // access/iterate 2nd level values
            function($v){
                return array_filter($v,'strlen');  // filter out subarray elements with zero-length values
            },$array  // the input array
        )
    )
);

Вот тот же код, что и в одной строке:

var_export(array_filter(array_map(function($v){return array_filter($v,'strlen');},$array)));

Вывод (как изначально указано в OP):

array (
)

*, если вы этого не сделаетехотите удалить пустые подмассивы, просто удалите внешний вызов array_filter().


Рекурсивный метод для многомерных массивов неизвестной глубины : Когда количество уровней в массивенеизвестны, рекурсия логическая техника.Следующий код будет обрабатывать каждый подмассив, удаляя значения нулевой длины и любые пустые подмассивы по мере их поступления. Вот демонстрация этого кода с несколькими примерами входных данных.

$array=[
    ['Name'=>'','Array'=>['Keep'=>'Keep','Drop'=>['Drop2'=>'']],'EmailAddress'=>'','Pets'=>0,'Children'=>null],
    ['Name'=>'','EmailAddress'=>'','FavoriteNumber'=>'0']
];

function removeEmptyValuesAndSubarrays($array){
   foreach($array as $k=>&$v){
        if(is_array($v)){
            $v=removeEmptyValuesAndSubarrays($v);  // filter subarray and update array
            if(!sizeof($v)){ // check array count
                unset($array[$k]);
            }
        }elseif(!strlen($v)){  // this will handle (int) type values correctly
            unset($array[$k]);
        }
   }
   return $array;
}

var_export(removeEmptyValuesAndSubarrays($array));

Выходные данные:

array (
  0 => 
  array (
    'Array' => 
    array (
      'Keep' => 'Keep',
    ),
    'Pets' => 0,
  ),
  1 => 
  array (
    'FavoriteNumber' => '0',
  ),
)

Если кто-нибудь обнаружит входной массив, который нарушает мой рекурсивный методПожалуйста, опубликуйте его (в его самой простой форме) как комментарий, и я обновлю свой ответ.

1 голос
/ 24 января 2017

Попробуйте с:

$array = array_filter(array_map('array_filter', $array));

Пример:

$array[0] = array(
   'Name'=>'',
   'EmailAddress'=>'',
);
print_r($array);

$array = array_filter(array_map('array_filter', $array));

print_r($array);

Выход:

Array
(
    [0] => Array
        (
            [Name] => 
            [EmailAddress] => 
        )
)

Array
(
)
...