21

I need to remove empty entries on multilevel arrays. For now I can remove entries with empty sub-arrays, but not empty arrays... confused, so do I... I think the code will help to explain better...

<?php

/**
 * 
 * This function remove empty entries on arrays
 * @param array $array
 */
function removeEmptysFromArray($array) {

    $filtered = array_filter($array, 'removeEmptyItems');
    return $filtered;
}

/**
 * 
 * This is a Callback function to use in array_filter()
 * @param array $item
 */
function removeEmptyItems($item) {

    if (is_array($item)) {
        return array_filter($item, 'removeEmptyItems');
    }

    if (!empty($item)) {
        return true;  
    }
}


$raw = array(
    'firstname' => 'Foo',
    'lastname'  => 'Bar',
    'nickname' => '',
    'birthdate' => array( 
        'day'   => '',
        'month' => '',
        'year'  => '',
    ),
    'likes' => array(
        'cars'  => array('Subaru Impreza WRX STi', 'Mitsubishi Evo', 'Nissan GTR'),
        'bikes' => array(),
    ),
);

print_r(removeEmptysFromArray($raw));

?>

Ok, this code will remove "nickname", "birthdate" but is not removing "bikes" that have an empty array.

My question is... How to remove the "bikes" entry?

Best Regards,

Sorry for my english...

André
  • 23,203
  • 42
  • 115
  • 174

7 Answers7

40

Try this code:

<?php
function array_remove_empty($haystack)
{
    foreach ($haystack as $key => $value) {
        if (is_array($value)) {
            $haystack[$key] = array_remove_empty($haystack[$key]);
        }

        if (empty($haystack[$key])) {
            unset($haystack[$key]);
        }
    }

    return $haystack;
}

$raw = array(
    'firstname' => 'Foo',
    'lastname'  => 'Bar',
    'nickname' => '',
    'birthdate' => array(
        'day'   => '',
        'month' => '',
        'year'  => '',
    ),
    'likes' => array(
        'cars'  => array('Subaru Impreza WRX STi', 'Mitsubishi Evo', 'Nissan GTR'),
        'bikes' => array(),
    ),
);

print_r(array_remove_empty($raw));
Alessandro Desantis
  • 13,548
  • 1
  • 25
  • 31
  • 2
    Thanks, just used it. One addition: if you want to remove "whitespaced" strings in array values also, then add a one little "elseif" clause: if (is_array($value)) { $haystack[$key] = array_remove_empty($haystack[$key]); } elseif(is_string($haystack[$key])) { $haystack[$key] = trim($value); } that way array(array(" ", ' ')) will be returned as empty also. – arunas_t Dec 17 '13 at 15:54
  • Always use \_\_FUNCTION__ in recursive calls to make your function portable. – Alex Skrypnyk Sep 08 '15 at 10:10
  • 2
    @ThanhTrung , he's calling array_remove_empty from inside array_remove_empty. If he were to rename the function, there would no longer be an array_remove_empty function to call. If the internal call was done by assigning `$fn = __FUNCTION__` and then calling $fn, it would work whatever the function was named. An alternative of course is *be careful when you rename functions and ensure you replaced all the **proper** function name's occurrences*. Especially if you rename a function to avoid name clashes, when the function will still exist, **but as a completely different function**. – LSerni Oct 28 '15 at 13:02
1

I think this should solve your problem.

$retArray =array_filter($array, arrayFilter);

function arrayFilter($array) {
     if(!empty($array)) {
         return array_filter($array);
     }
}
Thyagi
  • 184
  • 1
  • 6
1

Here is my solution, it will remove exactly specified list of empty values recursively:

/**
 * Remove elements from array by exact values list recursively
 *
 * @param array $haystack
 * @param array $values
 *
 * @return array
 */
function array_remove_by_values(array $haystack, array $values)
{
    foreach ($haystack as $key => $value) {
        if (is_array($value)) {
            $haystack[$key] = array_remove_by_values($haystack[$key], $values);
        }

        if (in_array($haystack[$key], $values, true)) {
            unset($haystack[$key]);
        }
    }

    return $haystack;
}

You can use it like this:

$clean = array_remove_by_values($raw, ['', null, []]);

Note, it removes empty sub arrays if you pass [] as one of values.

Vedmant
  • 1,738
  • 1
  • 22
  • 31
1
array_filter(explode('/', '/home/teste sdsd/   /'), 'trim');
//Result
[
     1 => "home",
     2 => "teste sdsd",
]

//-----------
array_filter(explode('/', '/home/teste sdsd/   /'), 'strlen')
//Result
  [
     1 => "home",
     2 => "teste sdsd",
     3 => "   ",
   ]
0

Recursively clear multidimensional array of empty'ish items:

final class ArrayCleaner
{
    public static function clean(array $value): array
    {
        foreach ($value as $k => $v) {
            if (\is_array($v)) {
                $value[$k] = self::clean($v);

                if (0 == \count($value[$k])) {
                    unset($value[$k]);
                }
            } elseif (empty($v)) {
                unset($value[$k]);
            }
        }

        return $value;
    }
}

Unit test:

final class ArrayCleanerTest
{
    public function testItCleans(): void
    {
        $input = [
            'empty_string_to_remove' => '',
            'empty_int_to_remove' => 0,
            'empty_string_number_to_remove' => '0',
            'value_to_keep' => 5,
            'empty_array_to_remove' => [],
            'empty_array_of_empty_arrays_to_remove' => [
                'one' => [],
                'two' => [],
                'three' => [false, null, '0'],
            ],
            'array_to_keep_1' => [
                'value' => 1,
            ],
            'array_to_keep_2' => [
                'empty_to_remove' => [],
                'array_to_keep' => ['yes'],
            ],
        ];

        $expected = [
            'value_to_keep' => 5,
            'array_to_keep_1' => [
                'value' => 1,
            ],
            'array_to_keep_2' => [
                'array_to_keep' => ['yes'],
            ],
        ];

        $this->assertEquals($expected, ArrayCleaner::clean($input));
    }
}

Working proof of concept at 3v4l.org

emix
  • 14,448
  • 10
  • 62
  • 82
-1

My function:

function removeEmptyItems($item)
{
    if (is_array($item)) {
        $item = array_filter($item, 'removeEmptyItems');
    }
    return !empty($item);
}

$nonEmpty = array_filter($raw, 'removeEmptyItems');
JustAC0der
  • 2,352
  • 3
  • 27
  • 34
-2

If you want array_filter to work recursively, you'll need to make sure that the subsequent calls may edit the deeper nested items of the array. Short: You'll need to pass it by reference:

function removeEmptyItems(&$item) {
    if (is_array($item) && $item) {
        $item = array_filter(&$item, 'removeEmptyItems');
    }

    return !!$item;
}
rodneyrehm
  • 13,169
  • 38
  • 56