130

I have a collection which I want to iterate and modify while I fetch some of its elements. But I could't find a way or method to remove that fetched element.

$selected = []; 
foreach ($collection as $key => $value) {
      if ($collection->selected == true) {
          $selected[] = $value;
          unset($value);
      }
}

This is just a representation of my question for demonstration.

After @Ohgodwhy advice the forget() function I checked it again and saw that I actually misunderstood the function. It was exactly as I was looking for.

So for working solution I have added $collection->forget($key) inside the if statement.

Below is the working solution of my problem, using @Ohgodwhy's solution:

$selected = []; 
foreach ($collection as $key => $value) {
      if ($collection->selected == true) {
          $selected[] = $value;
          $collection->forget($key);
      }
}

(this is just a demonstration)

Haritsinh Gohil
  • 5,818
  • 48
  • 50
Skeletor
  • 3,201
  • 4
  • 30
  • 51
  • 1
    I'd suggest not to store your items in an array but create a new collection and adding the elements to it through push. – Amarnasan Jun 02 '16 at 10:23
  • @Amarnasan How would go about that? I don't need it right now but I think I may need it in the future – Bruno Francisco Feb 05 '18 at 22:07
  • have a look here: https://stackoverflow.com/a/58769554/655224. your `if` condition `$collection->selected == true` makes no sense. why checking the property `selected` of the `collection` object not of the `value`? if the property is indeed inside `collection` check it once outside of your loop. – algorhythm Nov 08 '19 at 15:36

6 Answers6

192

You would want to use ->forget()

$collection->forget($key);

Link to the forget method documentation

Ohgodwhy
  • 49,779
  • 11
  • 80
  • 110
  • 1
    Yes actually i misunderstood forget(). i thought $key parameter removes all given keys. now i was able to use it right in the loop with a if statement. – Skeletor Jun 02 '16 at 10:18
  • 35
    `forget()` is cool compared to `delete()` or `remove()`, but hell, I had to come here to find out how to remove an item :) – Attila Fulop Feb 23 '17 at 09:22
  • what about if you want to delete entire object? – StealthTrails Feb 28 '18 at 03:55
  • 7
    @Adamnick With `forget` you'd need to know the `index` of the object in the array. What you want is probably `filter()` – Ohgodwhy Feb 28 '18 at 18:14
  • For anyone looking at this now, the link in the original question is broken, but you can find the same documentation here https://laravel.com/docs/5.8/collections#method-forget – Bryce Meyer Mar 07 '20 at 10:34
  • **this may help someone** foreach ($users as $key => $user) { $user_categories = User_category::where('user_id', $user->id)->exists(); if (!$user_categories) { $users = $users->forget($key); } } – Imran_Developer Dec 23 '21 at 14:40
46

Or you can use reject method

$newColection = $collection->reject(function($element) {
    return $item->selected != true;
});

or pull method

$selected = []; 
foreach ($collection as $key => $item) {
      if ($item->selected == true) {
          $selected[] = $collection->pull($key);
      }
}
huuuk
  • 4,597
  • 2
  • 20
  • 27
20

Laravel Collection implements the PHP ArrayAccess interface (which is why using foreach is possible in the first place).

If you have the key already you can just use PHP unset.

I prefer this, because it clearly modifies the collection in place, and is easy to remember.

foreach ($collection as $key => $value) {
    unset($collection[$key]);
}
andrewtweber
  • 24,520
  • 22
  • 88
  • 110
11

I'm not fine with solutions that iterates over a collection and inside the loop manipulating the content of even that collection. This can result in unexpected behaviour.

See also here: https://stackoverflow.com/a/2304578/655224 and in a comment the given link http://php.net/manual/en/control-structures.foreach.php#88578

So, when using foreach it seems to be ok but IMHO the much more readable and simple solution is to filter your collection to a new one.

/**
 * Filter all `selected` items
 *
 * @link https://laravel.com/docs/7.x/collections#method-filter
 */
$selected = $collection->filter(function($value, $key) {
    return $value->selected;
})->toArray();
algorhythm
  • 8,530
  • 3
  • 35
  • 47
1

You can use methods of Collection like pull, forget, reject etc.

But every Collection method returns an entirely new Collection instance.

Doc link: https://laravel.com/docs/8.x/collections#introduction

  • 1
    Your are wrong. "Unlike most other collection methods, forget does not return a new modified collection; it modifies the collection it is called on." – Michal - wereda-net Jun 21 '23 at 14:52
  • @Michal-wereda-net this person is not wrong but could have specified in the different context. regardless Ali Akbar Afridi also cited the laravel documentation – jovialcore Aug 16 '23 at 12:40
0

If you know the key which you unset then put directly by comma separated

unset($attr['placeholder'], $attr['autocomplete']);
Kaushik shrimali
  • 1,178
  • 8
  • 15
  • I got a special case I got an item listing system where a new property is being returned in latest properties collection and also in unrated collection which I'm all showing on one page. I want those items already in the first list to be popped out of the second lisg how do I do this. Keep in mind you can't tell the index the item will appear in. Can I do something like ```$collection->forget($item->id) ``` ? – Software Developer Apr 22 '20 at 14:59