如何递归地删除数组中的空条目?

23
我需要删除多级数组中的空条目。目前我可以删除具有空子数组的条目,但无法删除空数组...感到困惑,我也是...我认为代码会更好地解释。
/**
 * 
 * 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));

这段代码将删除nicknamebirthdate,但不会删除空数组的bikes
我的问题是... 如何删除bikes条目?

你为什么想要移除它们? - John
9个回答

43

试试这段代码:

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

2
谢谢,我刚用了它。还有一个补充:如果你想要删除数组值中的“空格”字符串,那么添加一个小的“elseif”子句:if (is_array($value)) { $haystack[$key] = array_remove_empty($haystack[$key]); } elseif(is_string($haystack[$key])) { $haystack[$key] = trim($value); } 这样,array(array(" ", ' ')) 也将被视为空。 - arunas_t
在递归调用中,始终使用__FUNCTION__以使您的函数具有可移植性。 - Alex Skrypnyk
2
@ThanhTrung,他正在从array_remove_empty内部调用array_remove_empty。如果他重命名函数,就不再有array_remove_empty函数可供调用了。如果通过分配$fn = __FUNCTION__并调用$fn来进行内部调用,则无论函数命名如何都可以工作。当然,另一种选择是在重命名函数时要小心,并确保替换了所有正确的函数名称出现。特别是如果您将函数重命名以避免名称冲突,而该函数仍将存在,但作为完全不同的函数 - LSerni

2

以下是我的解决方案,它可以递归地删除指定列表中的空值:

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

你可以这样使用它:

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

请注意,如果您将[]作为值之一传递,则会删除空的子数组。

2
这对于ACF组数组非常有效,谢谢! - return_false

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
我认为这应该解决你的问题。
$retArray =array_filter($array, arrayFilter);

function arrayFilter($array) {
     if(!empty($array)) {
         return array_filter($array);
     }
}

0

递归清除多维数组中的空项:

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

单元测试:

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

3v4l.org上的工作概念验证


0

array_filter()empty()在问题输入上可能是安全的,但对于公共通用性它们不可靠。这些本地函数将所有"falsey"值视为可过滤/空值。详见 empty()文档关于其贪婪确定空值的细节。

如果有意图的话,我建议明确检查(数据类型特别是)空字符串。这样你就不会无意中破坏有意义的数据了。我选择将$value声明为引用,以避免迭代数组的副本 -- 这使我可以使用$value来改变/覆盖数组数据,而不是使用更冗长的$array[$key](当不使用unset()时)。

代码:(带有各种falsey值的演示)

function recursivelyRemoveEmpties(array $array): array
{
    foreach ($array as $key => &$value) {
        if (is_array($value)) {
            $value = recursivelyRemoveEmpties($value);
            if (!$value) {
                unset($array[$key]);
            }
            continue;
        }
        if ($value === '') {
            unset($array[$key]);
        }
    }

    return $array;
}

var_export(recursivelyRemoveEmpties($raw));

*请注意,此脚本不适用于数据有效负载中的对象。


-1

我的函数:

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

$nonEmpty = array_filter($raw, 'removeEmptyItems');

-1

基于递归函数的简单而优雅的解决方案。不喜欢之前答案中的任何解决方案。删除空的子数组/子值:

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

-2

如果你想让array_filter递归地工作,你需要确保后续的调用可以编辑数组中更深层嵌套的项目。简而言之:你需要通过引用传递它:

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

    return !!$item;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接