77

I have a foreach loop set up to go through my array, check for a certain link, and if it finds it removes that link from the array.

My code:

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

But it doesn't remove the array entires. It's probably something to do with $images[$image], as that's not the key of the array entry, only the content? Is there a way to do this without incorporating a counter?

Thanks.

EDIT: Thanks guys, but now I have another problem where the array entries don't actually get deleted.

My new code:

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 is actuallty a two-dimensional array now hence why I need $images[1]. I have checked and it successfully goes around the array elements, and some elements do actually have some of those URLs in that I wish to delete, but they're not getting deleted. This is my $images array:

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
        )

)

Thanks!

Matt
  • 1,083
  • 2
  • 10
  • 15
  • 2
    I would also suggest if(in_array($image, array('http://i27.tinypic.com/29yk345.gif', 'http://img3.abload.de/img/10nx2340fhco.gif', 'http://i42.tinypic.com/9pp2456x.gif')). Makes it more readable ;) – Olivier Lalonde Jan 05 '10 at 20:37
  • 3
    Since you changed the array you're iterating, that needs to be reflected in your call to unset - unset($images[1][$key]); – bish Jan 05 '10 at 21:03
  • And the parenthesis in the if statement are wrong but I guess this just typo (otherwise you would get an error message) – Felix Kling Jan 05 '10 at 21:10
  • "Note: When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop. As foreach relies on the internal array pointer changing it within the loop may lead to unexpected behavior." Taken from the php manual – Vlad Balmos Dec 07 '11 at 15:05

9 Answers9

94
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]);
    }
}
Besnik
  • 6,469
  • 1
  • 31
  • 33
hsz
  • 148,279
  • 62
  • 259
  • 315
76

Try that:

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

Normally, foreach operates on a copy of your array so any changes you make, are made to that copy and don't affect the actual array.

So you need to unset the values via $images[$key];

The reference on &$image prevents the loop from creating a copy of the array which would waste memory.

Knowledge Craving
  • 7,955
  • 13
  • 49
  • 92
selfawaresoup
  • 15,473
  • 7
  • 36
  • 47
  • Thanks. I think what you're saying is related to my problem (see edit). Even if I add a `&` though it still doesn't work. – Matt Jan 05 '10 at 21:03
  • 14
    "The reference on &$image prevents the loop from creating a copy of the array which would waste memory." <- what I was looking for :) – marcovtwout Jun 22 '12 at 13:11
  • 7
    After the loop you should `unset($image);`. – Ja͢ck Nov 21 '14 at 04:59
  • using & actually waste memory, for complete explanation, please read : https://flyleafbd.wordpress.com/2011/06/07/the-truth-about-php-variables/ – Bruno May 20 '16 at 13:52
  • @bruno are you sure that this is the case with PHP 7? The article is from 2011 and it mentions the ancient PHP 4 – IanDess Aug 13 '16 at 13:53
  • @lanDess you're rigth, i didn"t know that php7 has moved away from zval, but it seem to still be valid, please read : https://schlueters.de/blog/archives/180-References-Still-bad-in-PHP-7.html (ok, one source is not sufficient, so let's keep a doubt in mind) – Bruno Aug 16 '16 at 07:42
  • 1
    @lanDess I found another source : https://nikic.github.io/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html section "References" => so, OK, in PHP7, this probleme is solved and using reference isn't a performance issue – Bruno Aug 16 '16 at 07:51
  • Indeed the reference is not necessary. Arrays are always passed by reference until they are modified – gsouf May 03 '17 at 17:34
  • @Ja͢ck Why do we need `After the loop you should unset($image);` ? – Ibrahim Mohamed May 20 '18 at 16:35
  • 3
    @IbrahimShendy safety, in case you reuse that variable later; if not, it would modify the last element of the array – Ja͢ck May 20 '18 at 22:11
13

To answer the initial question (after your edit), you need to unset($images[1][$key]);

Now some more infos how PHP works: You can safely unset elements of the array in foreach loop, and it doesn't matter if you have & or not for the array item. See this code:

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

This prints:

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

So as you can see, if you unset correct thing within the foreach loop, everything works fine.

Tomas M
  • 6,919
  • 6
  • 27
  • 33
7

You can use the index of the array element to remove it from the array, the next time you use the $list variable, you will see that the array is changed.

Try something like this

foreach($list as $itemIndex => &$item) {

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

}
webmaster
  • 1,960
  • 24
  • 29
4

$image is in your case the value of the item and not the key. Use the following syntax to get the key too:

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

Now you can delete the item with unset($images[$key]).

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • This might work, but it will still copy the whole array to execute the foreach loop. So it's a waste of memory. If I'm not mistaken, the approach with references (see my answer) is also faster than resolving the key/value pair each time the unset happens. – selfawaresoup Jan 05 '10 at 20:36
  • The second part is actually not so true. Sorry. Unsetting by reference does of course not work. – selfawaresoup Jan 05 '10 at 20:42
  • @Techpriester: `foreach` does always work on an internal copy. – Gumbo Jan 05 '10 at 20:43
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]); }                               
}

!!foreach($images as $key=>$image

cause $image is the value, so $images[$image] make no sense.

Peter Porfy
  • 8,921
  • 3
  • 31
  • 41
1

One solution would be to use the key of your items to remove them -- you can both the keys and the values, when looping using foreach.

For instance :

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

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

var_dump($arr);

Will give you this array, in the end :

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


Which means that, in your case, something like this should do the trick :

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]);
    }
}
Pascal MARTIN
  • 395,085
  • 80
  • 655
  • 663
1

You would also need a

$i--;

after each unset to not skip an element/

Because when you unset $item[45], the next element in the for-loop should be $item[45] - which was [46] before unsetting. If you would not do this, you'd always skip an element after unsetting.

Bojangles
  • 99,427
  • 50
  • 170
  • 208
  • 4
    But unset() will not change the array index so I don't think this $i-- is needed here. If the method array_splice() was used, then the elements would be shifted to cover the deleted hole and $i-- is necessary. – zhujy_8833 Sep 18 '12 at 23:25
0

Sorry for the late response, I recently had the same problem with PHP and found out that when working with arrays that do not use $key => $value structure, when using the foreach loop you actual copy the value of the position on the loop variable, in this case $image. Try using this code and it will fix your problem.

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();
Volker E.
  • 5,911
  • 11
  • 47
  • 64
jameslimousin
  • 330
  • 3
  • 11