How to remove empty entries of an array recursively?
Asked Answered
D

9

24

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.

/**
 * 
 * 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));

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?

Dyun answered 8/10, 2011 at 11:40 Comment(0)
G
46

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));
Gapin answered 8/10, 2011 at 11:50 Comment(4)
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.Gasman
Always use __FUNCTION__ in recursive calls to make your function portable.Neuritis
@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.Hygiene
NOTE: be careful with empty($haystack[$key]) since it not only removes empty strings or null values, but also: 0 (integer) "0" (zero string) false (boolean) true (boolean). w3schools.com/php/func_var_empty.aspCarrack
D
2

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.

Derbent answered 6/8, 2017 at 17:7 Comment(0)
F
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 => "   ",
   ]
Fetiparous answered 24/11, 2021 at 20:43 Comment(0)
C
0

I think this should solve your problem.

$retArray =array_filter($array, arrayFilter);

function arrayFilter($array) {
     if(!empty($array)) {
         return array_filter($array);
     }
}
Cosimo answered 10/11, 2015 at 8:19 Comment(0)
C
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

Cortez answered 16/8, 2020 at 11:14 Comment(0)
C
0

array_filter() and empty() may be safe to leverage for the asker's sample input, but they are not reliable for public general use. These native functions will treat all "falsey" values as filterable/empty. See the documentation for empty() for details on its greedy determination of emptiness.

I recommend explicitly checking (data type specifically) for empty string strings if that is the intent. This way you don't inadvertently destroy meaningful data. I am choosing to declare $value as a reference to avoid iterating a copy of the array -- this allows me to mutate/overwrite array data with $value instead of the more verbose $array[$key] (when not using unset().

Code: (Demo with an assortment of falsey values)

function recursivelyRemoveEmpties(array $array): array
{
    foreach ($array as $key => &$value) {  // modify by reference to affect original array
        if (is_array($value)) {
            $value = recursivelyRemoveEmpties($value);
            if (!$value) {  // if the array is empty
                unset($array[$key]);
            }
            continue;
        }
        if ($value === '') { // add additional qualifying conditions here only
            unset($array[$key]);
        }
    }

    return $array;
}

var_export(recursivelyRemoveEmpties($raw));

*Note that this script is not designed to accommodate objects in the data payload.

Columba answered 5/4, 2023 at 22:24 Comment(0)
G
-1

My function:

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

$nonEmpty = array_filter($raw, 'removeEmptyItems');
Gwenette answered 16/10, 2020 at 13:59 Comment(0)
L
-1

Simple and elegant solution based on recursive function. Dont liked any solution from the prev. answers. Removes empty sub arrays/sub values:

/**
 * Clean array from empty values
 * @param $array
 * @return array|mixed
 */
function array_filter_recursive($array){
    if (!is_array($array)) return $array;
    foreach ( $array as $key=>$item){
        if (is_array($item))
            $array[$key] = array_filter_recursive($item);
    }
    return array_filter($array);
}
Lannie answered 5/4, 2023 at 12:26 Comment(0)
G
-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;
}
Goebbels answered 8/10, 2011 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.