如何在foreach循环中删除数组元素?

156

我想使用foreach循环遍历一个数组来检查值是否存在。如果这个值确实存在,我希望删除包含该值的元素。

我有以下代码:

foreach($display_related_tags as $tag_name) {
    if($tag_name == $found_tag['name']) {
        // Delete element
    }
}

我不知道如何在找到值后删除元素。怎样才能删除它?

针对这个问题,我必须使用 foreach。虽然可能还有其他替代方案可以使用,欢迎分享。


这个问题缺少[mcve]。它不是一个很好的规范参考,回答者有自由去解释输入数据以便多样化推荐解决方案——这对研究者体验不利。 - mickmackusa
7个回答

256
如果您也获得了该键,您可以像这样删除该项目:
foreach ($display_related_tags as $key => $tag_name) {
    if($tag_name == $found_tag['name']) {
        unset($display_related_tags[$key]);
    }
}

5
关于使用 $key => &$tag_name 进行优化的一些附加信息。https://dev59.com/WnI-5IYBdhLWcg3wHUhB#2008893 - Justin
5
请注意,未设置项目的索引数组在 json_encode() 后可能会被表示为对象而不是数组。您可以在 foreach 循环后使用 $display_related_tags = array_values($display_related_tags); 来解决这个问题,使其变成数组形式。 - Márton Tamás
1
请注意,这里的技巧是向foreach循环添加一个值 ;-) - Mr Washington
6
请查看 @Neils 的回答。如果你使用 stdClasses 数组,你可能会遇到意想不到的错误。你喜欢意外行为吗?我不喜欢。 - happy_marmoset
@happy_marmoset Neils 的回答没有帮助。代码片段 $projects = array_filter($projects, function ($project) { return count($project->roles) > 0; }); 将结果转换为对象。 - Paritosh
重要提示:如果您希望保持数组的有序性,那么在此之后需要调用 display_related_tags = array_values(display_related_tags); - guyaloni

48
更好的解决方案是使用array_filter函数:
$display_related_tags =
    array_filter($display_related_tags, function($e) use($found_tag){
        return $e != $found_tag['name'];
    });

根据 PHP 的文档所述:

由于在 PHP 5 中 foreach 依赖于内部数组指针,因此在循环内部更改它可能会导致意外行为。

在 PHP 7 中,foreach 不使用内部数组指针。


请注意,第三个参数应该是ARRAY_FILTER_USE_KEY,以便将键传递为$e。 - namezero
@namezero 好的,那这对此有什么影响吗? - AbraCadaver
@AbraCadaver 从文档(https://www.php.net/manual/en/function.array-filter.php)中可以看到: ARRAY_FILTER_USE_KEY - 将键作为回调函数的唯一参数传递,而不是值 ARRAY_FILTER_USE_BOTH - 将值和键都作为回调函数的参数传递,而不是值 默认值为0,它将仅将值作为回调函数的参数传递。 也就是说,在这种情况下再次阅读答案当然不会有影响,正如你所说的那样。 - namezero
重要提示:如果您希望保持数组的有序性,那么在此之后需要调用 display_related_tags = array_values(display_related_tags); - guyaloni
1
那么,我们现在可以说,在PHP 7中直接从数组中取消设置项目是安全的吗?从编码人员的角度来看,它似乎比使用array_filter更加简洁(我不确定背景中的实际实现)。 - userfuser

12
foreach($display_related_tags as $key => $tag_name)
{
    if($tag_name == $found_tag['name'])
        unset($display_related_tags[$key];
}

7
“unlink”是指取消文件链接,与变量或者数组无关。也许你的意思是“unset”? - Armen Michaeli

6

不要使用foreach()循环遍历数组,使用array_search()查找正确的键会更快。在小型数组中,为了更好的可读性,我会选择使用foreach,但对于更大的数组或经常执行的代码,这种方法应该更加优化:

$result=array_search($unwantedValue,$array,true);
if($result !== false) {
  unset($array[$result]);   
}

需要使用严格比较运算符!==,因为array_search()可能会返回$unwantedValue的索引值0。

此外,上面的示例仅会删除第一个$unwantedValue的值,如果$unwantedValue在$array中可能出现多次,则应该使用array_keys()来查找所有的值:

$result=array_keys($array,$unwantedValue,true)
foreach($result as $key) {
  unset($array[$key]);
}

请查看http://php.net/manual/zh/function.array-search.php了解更多信息。


0

已经有一些回答说明如何取消设置。与其在所有类中重复代码,不如创建下面这样的函数,并在需要时在代码中使用它。在业务逻辑中,有时您不想公开某些属性。请参见下面一行代码以进行删除。

public static function removeKeysFromAssociativeArray($associativeArray, $keysToUnset)
{
    if (empty($associativeArray) || empty($keysToUnset))
        return array();

    foreach ($associativeArray as $key => $arr) {
        if (!is_array($arr)) {
            continue;
        }

        foreach ($keysToUnset as $keyToUnset) {
            if (array_key_exists($keyToUnset, $arr)) {
                unset($arr[$keyToUnset]);
            }
        }
        $associativeArray[$key] = $arr;
    }
    return $associativeArray;
}

调用方式如下:

removeKeysFromAssociativeArray($arrValues, $keysToRemove);

我从不在已经声明的变量上调用empty()函数。 - mickmackusa

0

如果您有这样的情况,需要从foreach数组中删除多个值,在这种情况下,您必须通过引用在foreach中传递值: 我试图解释这种情况:

foreach ($manSkuQty as $man_sku => &$man_qty) {

               foreach ($manufacturerSkus as $key1 => $val1) {

  // some processing here and unset first loops entries                     
 //  here dont include again for next iterations
                           if(some condition)
                            unset($manSkuQty[$key1]);

                        }
               }
}

在第二个循环中,您想要取消第一个循环的条目,以便它们不会再次出现在迭代中,以提高性能,否则也要从内存中取消,因为它们在内存中存在并将在迭代中出现。

-2
我们可以使用 while 循环和 array_splice
$i=0;
while ($i < count ($MyArray))
{
    if ( $MyArray[$i]->Property == $Value) 
        array_splice($MyArrays, $i);
        // as we removed an element, we do not increment $i array index
    else
        $i++;
}

我们已经从数组中删除了所有具有目标属性的元素,这些元素的值符合预期。

我不知道你从哪里得到了“数组没有键访问”的概念,但这绝对是错误的。在PHP中,没有没有键访问的数组。 - Your Common Sense
这段代码根本没有意义。你真的尝试过运行它吗? - Your Common Sense
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

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