Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

SNaRe's avatar
Level 7

Search and skip to Next item in collection

I have a collection below, which I would like to search and get the contents of the next items https://laravel.com/docs/5.6/collections#method-where

where() function would find for example.

$collection->where('product_id', '342')->where('customer_id', '62')

How can I get the contents of the next one? which is in this case +"product_id": 456 +"customer_id": 933

When I run the code above I got the key. Maybe if I can reach it and increment it 1 and if there is a way like $collection->get(x) it would solve my problem I suppose

Collection {#630 ▼
  #items: array:14 [▼
    0 => {#638 ▼
      +"product_id": 378
      +"customer_id": 936
    }
    1 => {#635 ▼
      +"product_id": 342
      +"customer_id": 62
    }
    2 => {#597 ▼
      +"product_id": 456
      +"customer_id": 933
    }
    3 => {#632 ▼
      +"product_id": 450
      +"customer_id": 935
    }
    4 => {#633 ▼
      +"product_id": 435
      +"customer_id": 934
    }
  ]
}
0 likes
4 replies
rin4ik's avatar
$next = $collection->where('product_id'>'342'->where('customer_id'>'62'));
mdeorue's avatar

You can use this snipet.

$collection = $collection->getIterator();
$current = current($collection);
$next = next($collection);

Regards

SNaRe's avatar
Level 7

@rin4ik it just find but doesn't find the next one.

@mdeorue As far as I understood, the snippet you shared return $collection as the new $collection for the next So that If I dd($collection) I will get the next one? I tried but I couldn't succeed.

BTW I solved like this but it doesn't seem to be the best way(this is nightmare).

$current_key =  $unanswered_messages_list
->where('product_id',$product)
->where('customer_id',$customer)->keys()->first();
$next_key = $current_key +1;
$next_page = $unanswered_messages_list->only($next_key)->first();
jjudge's avatar

I used a reduce function to do this. It should work efficiently for small lists.

$nextItem = $collection->reduce(function ($carry, $item) {
    if (! is_bool($tiem)) {
        return $item;
    }

    if (test-for-matching-record) {
        return true;
    }

    if ($carry === true) {
        return $item;
    }

    return false;
}, false);

$finalNextAfterMatchItem = is_bool($nextItem) ? null : $nextItem;

So a carry of false means it has not found a match, and a carry of true means it has found a match. The next item after true will be the item we want, so we set carry to the item at that point. After that, we pass that item down through the remaining iterations. There is no way to break out of the reduce() loop early once we have found that match, hence not wanting to use this technique for long lists.

Instead of the three-state true/false/item for carry, you could use a structure with a separate "found" flag and item value. That will save doing the expression at the end.

Update, just for when I come looking for the answer again:

$nextItemAfterMatchedItem = $collection->reduce(function ($carry, $item) {
    if ($carry->next !== null) {
        // Got it already.
        return $carry;
    }

    if ($carry->found === true) {
        // Found the matching item on the last iteration.
        $carry->next = $item;
    }

    if ($carry->found === false && test-for-matching-record) {
        // Found the matching item this iteration.
        $carry->found = true;
    }

    return $carry;
}, (object)['found' => false, 'next' => null])->next;

Please or to participate in this conversation.