在 foreach 循环中取消设置数组值

80

我设置了一个foreach循环来遍历我的数组,检查是否存在特定的链接,如果找到则从该数组中删除该链接。

我的代码:

foreach($images as $image)
{
    if($image == 'http://i27.tinypic.com/29yk345.gif' ||
    $image == 'http://img3.abload.de/img/10nx2340fhco.gif' ||
    $image == 'http://i42.tinypic.com/9pp2456x.gif')
    {
        unset($images[$image]);
    }
}

但它并没有删除数组条目。这可能与$images[$image]有关,因为它不是数组条目的键,只是内容?有没有一种方法可以在不使用计数器的情况下完成这个操作?

谢谢。

编辑:谢谢大家,但现在我有另一个问题,那就是数组条目实际上并没有被删除。

我的新代码:

foreach($images[1] as $key => $image)
{
    if($image == 'http://i27.tinypic.com/29yk345.gif')
    $image == 'http://img3.abload.de/img/10nx2340fhco.gif' ||
    $image == 'http://i42.tinypic.com/9pp2456x.gif')
    {
        unset($images[$key]);
    }
}

$images现在实际上是一个二维数组,因此我需要$images[1]。我已经检查过了,它成功地遍历了数组元素,有些元素确实包含我想要删除的URL,但它们没有被删除。这是我的$images数组:

Array
(
    [0] => Array
        (
            [0] => useless
            [1] => useless
            [2] => useless
            [3] => useless
            [4] => useless
        )

    [1] => Array
        (
            [0] => http://i27.tinypic.com/29yk345.gif
            [1] => http://img3.abload.de/img/10nx2340fhco.gif
            [2] => http://img3.abload.de/img/10nx2340fhco.gif
            [3] => http://i42.tinypic.com/9pp2456x.gif
        )

)

谢谢!


2
我还建议使用if(in_array($image, array('http://i27.tinypic.com/29yk345.gif', 'http://img3.abload.de/img/10nx2340fhco.gif', 'http://i42.tinypic.com/9pp2456x.gif'))来使代码更易读 ;) - Olivier Lalonde
3
由于您更改了正在迭代的数组,因此需要在调用unset时进行反映 - unset($images[1][$key]); - bish
而且if语句中的括号是错误的,但我猜这只是个打字错误(否则你会收到错误信息)。 - Felix Kling
注意:当foreach开始执行时,内部数组指针会自动重置为数组的第一个元素。这意味着在foreach循环之前不需要调用reset()。由于foreach依赖于内部数组指针的变化,因此在循环中更改它可能会导致意外的行为。 - Vlad Balmos
9个回答

95
foreach($images as $key => $image)
{
    if(in_array($image, array(
       'http://i27.tinypic.com/29ykt1f.gif',
       'http://img3.abload.de/img/10nxjl0fhco.gif',
       'http://i42.tinypic.com/9pp2tx.gif',
    ))
    {
        unset($images[$key]);
    }
}

感谢帮助,但我现在遇到了一些麻烦,无法真正删除一些数组元素。请参见第一个帖子中的编辑 :) - Matt
6
尝试使用 unset($images[1][$key]);。该语句的目的是从关联数组 $images 的第二个元素中删除指定键 $key 所对应的值。 - hsz

78

试试这个:

foreach ($images[1] as $key => &$image) {
    if (yourConditionGoesHere) {
        unset($images[1][$key])
    }
}
unset($image); // detach reference after loop  

通常情况下,foreach 在数组的副本上操作,所以您所做的任何更改都是针对该副本进行的,并不会影响实际的数组。

因此,您需要通过 $images[$key] 取消设置值;

&$image 上的引用防止循环创建一个数组副本,这将浪费内存。


14
“&$image” 的引用防止循环创建数组的副本,从而避免浪费内存。 - marcovtwout
7
循环结束后,您应该使用unset($image);来释放变量。 - Ja͢ck
1
@lanDess 我找到了另一个来源: https://nikic.github.io/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html 章节“引用”=> 因此,在PHP7中,这个问题得到了解决,并且使用引用不再是性能问题。 - Bruno
实际上,引用并不是必需的。数组在被修改之前始终按引用传递。 - gsouf
3
如果您稍后会再次使用该变量,为了安全起见,请修改数组的最后一个元素;如果不会再使用该变量,则会修改数组的最后一个元素。 - Ja͢ck
显示剩余5条评论

13

在您编辑后回答最初的问题,您需要使用unset($images[1][$key]);

现在更多关于PHP工作原理的信息: 您可以安全地在foreach循环中取消设置数组的元素,无论数组项是否有“&”. 请参阅以下代码:

$a=[1,2,3,4,5];
foreach($a as $key=>$val)
{
   if ($key==3) unset($a[$key]);
}
print_r($a);

这将打印:

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [4] => 5
)

因此,正如您所看到的,如果在foreach循环中取消正确的事物,则一切都可以正常工作。


你的意思是 $key==4 吗? - Andrei Nikolaenko

7
你可以使用数组元素的索引来从数组中删除它,下一次使用$list变量时,你会发现数组已经被更改。
尝试像这样做:
foreach($list as $itemIndex => &$item) {

   if($item['status'] === false) {
      unset($list[$itemIndex]);
   }

}

这个不起作用,请参见下面。https://dev59.com/WnI-5IYBdhLWcg3wHUhB#2008893 - Justin
请查看此方法失败的位置:http://ideone.com/Vv4DR8 - Justin
1
@Justin,那是因为你取消了$item而不是列表中的项目。我fork了你的代码,这个可以工作:http://ideone.com/SY0XC3 - rolandow
你是正确的。感谢 @rolandow 解决了这个问题! - Justin
不要忘记在foreach循环后使用unset($item) - Synexis

4

$image 在这里是项的值而不是键。使用以下语法可以获取键:

foreach ($images as $key => $value) {
    /* … */
}

现在你可以使用unset($images[$key])删除该项。

这个可能会有效果,但它仍然会复制整个数组来执行foreach循环。所以这是一种浪费内存的做法。 如果我没弄错的话,使用引用的方法(请看我的回答)比每次解析键/值对时都要快。 - selfawaresoup
第二部分实际上并不完全正确。抱歉。当然,通过引用取消设置是行不通的。 - selfawaresoup
@Techpriester:foreach 总是在内部副本上工作。 - Gumbo

1

foreach($images as $key=>$image)                                
{               
   if($image == 'http://i27.tinypic.com/29ykt1f.gif' ||    
   $image == 'http://img3.abload.de/img/10nxjl0fhco.gif' ||    
   $image == 'http://i42.tinypic.com/9pp2tx.gif')     
   { unset($images[$key]); }                               
}

由于$image表示的是value,因此$images[$image]没有意义。


失败。你应该使用 code sample - 而不是 blockquote。 ;) - hsz

1

一个解决方案是使用你的项目的键来删除它们 -- 当使用foreach循环时,你可以同时遍历键和值。

例如:

$arr = array(
    'a' => 123,
    'b' => 456,
    'c' => 789, 
);

foreach ($arr as $key => $item) {
    if ($item == 456) {
        unset($arr[$key]);
    }
}

var_dump($arr);

最终会给你这个数组:

array
  'a' => int 123
  'c' => int 789

这意味着,在您的情况下,类似这样的代码应该可以解决问题: < / p>
foreach($images as $key => $image)
{
    if($image == 'http://i27.tinypic.com/29yk345.gif' ||
    $image == 'http://img3.abload.de/img/10nx2340fhco.gif' ||
    $image == 'http://i42.tinypic.com/9pp2456x.gif')
    {
        unset($images[$key]);
    }
}

1

你还需要一个

$i--;

在每个unset之后不要跳过一个元素。

因为当你unset $item[45]时,for循环中的下一个元素应该是$item[45] - 在unset之前是[46]。如果你不这样做,那么在unset之后总会跳过一个元素。


4
但是 unset() 函数不会改变数组的索引,所以我认为这里不需要 $i--。如果使用 array_splice() 方法,则元素将被移动以填补已删除的空缺,$i-- 是必要的。 - zhujy_8833

0

抱歉回复晚了,我最近也遇到了PHP的同样问题,并发现当使用不使用$key => $value结构的数组时,在使用foreach循环时,实际上是复制了循环变量位置的值,即$image。尝试使用以下代码,它将解决您的问题。

for ($i=0; $i < count($images[1]); $i++)
{

    if($images[1][$i] == 'http://i27.tinypic.com/29yk345.gif' ||

    $images[1][$i] == 'http://img3.abload.de/img/10nx2340fhco.gif' ||

    $images[1][$i] == 'http://i42.tinypic.com/9pp2456x.gif')

    {

        unset($images[1][$i]);

    }

}

var_dump($images);die();

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