Подтвердить что ты не робот

Рекурсивно удалять пустые элементы и подмассивы из многомерного массива

Я не могу найти простого, прямолинейного решения старой проблемы удаления пустых элементов из массивов в 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" должен быть действительным обратным вызовом

Что я делаю неправильно?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

Ответ 4

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

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

Ответ 5

Попробуйте:

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

Ответ 6

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

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

Статический 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',
  ),
)

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