Как получить доступ к n-му элементу в коллекции Laravel?

Наверное, я нарушаю все правила, намеренно задавая повторяющийся вопрос ...

На другой вопрос принято отвечать. Очевидно, это решило проблему спрашивающего, но не ответило на заглавный вопрос.

Начнем с начала - метод first() реализован примерно так:

foreach ($collection as $item)
    return $item;

Очевидно, что это более надежно, чем использование $collection[0] или других предлагаемых методов.

Может не быть элемента с индексом 0 или индексом 15, даже если в коллекции 20 элементов. Чтобы проиллюстрировать проблему, возьмем эту коллекцию из документации:

$collection = collect([
    ['product_id' => 'prod-100', 'name' => 'desk'],
    ['product_id' => 'prod-200', 'name' => 'chair'],
]);

$keyed = $collection->keyBy('product_id');

Теперь, есть ли у нас какой-нибудь надежный (и желательно краткий) способ получить доступ к n-му элементу $keyed?

Мое собственное предложение было бы сделать:

$nth = $keyed->take($n)->last();

Но это будет давать неправильный элемент ($keyed->last()) всякий раз, когда $n > $keyed->count(). Как мы можем получить n-й элемент, если он существует, и null, если он не похож на first()?

Редактировать

Чтобы внести ясность, давайте рассмотрим этот сборник:

$col = collect([
    2 => 'a',
    5 => 'b',
    6 => 'c',
    7 => 'd']);

Первый элемент - $col->first(). Как получить второй?

$col->nth(3) должен возвращать 'c' (или 'c', если отсчитывается от 0, но это будет несовместимо с first()). $col[3] не сработает, просто вернет ошибку.

$col->nth(7) должен вернуть null, потому что седьмого элемента нет, их всего четыре. $col[7] не сработает, он просто вернет 'd'.

Вы можете перефразировать вопрос как «Как получить n-й элемент в порядке foreach?» если для кого-то это более понятно.


person Džuris    schedule 06.11.2016    source источник
comment
Как и в ответе на вопрос, который вы упомянули, вы можете сделать $collection->get($nth, 'some default value')   -  person tam5    schedule 06.11.2016
comment
@tam Он использует ключи точно так же, как [$nth] ...   -  person Džuris    schedule 06.11.2016


Ответы (4)


Я думаю, что более быстрый и эффективный с точки зрения памяти способ - использовать метод slice():

$collection->slice($n, 1);
person Alexey Mezenin    schedule 06.11.2016
comment
Это кажется приятным, но я не уверен в поведении $n > $collection->count(). Похоже, что slice() использует PHP array_slice(), и я не могу найти информацию о поведении, если $n превышает размер массива. Может быть, это не указано и ненадежно: | - person Džuris; 06.11.2016
comment
Он просто вернет пустую коллекцию. Вы даже можете легко проверить с помощью ->isEmpty() или empty($result). - person Alexey Mezenin; 06.11.2016
comment
Хорошо, тогда $collection->slice($n, 1)->fiirst() вернет n-й элемент, если он существует, и null в противном случае. Вроде здорово :) - person Džuris; 08.11.2016

Вы можете попробовать это, используя функцию values() как:

$collection->values()->get($n);
person Amit Gupta    schedule 06.11.2016
comment
На данный момент это кажется лучшим решением, не могу вспомнить пример, когда это не удается :) - person Džuris; 06.11.2016
comment
Это рабочее решение, но оно будет дублировать всю коллекцию и может убить приложение, если коллекция сама по себе большая (коллекция статей с отношениями или что-то подобное). - person Alexey Mezenin; 06.11.2016

Основываясь на ответе Алексея, вы можете создать макрос в AppServiceProvider (добавить его внутри метода регистрации):

use Illuminate\Support\Collection;

Collection::macro('getNth', function ($n) {
   return $this->slice($n, 1)->first();
});

а затем вы можете использовать это во всем своем приложении:

$collection = ['apple', 'orange'];

$collection->getNth(0) // returns 'apple'
$collection->getNth(1) // returns 'orange'
$collection->getNth(2) // returns null
$collection->getNth(3) // returns null
person Muhammad Syauqy    schedule 03.05.2019

Возможно, это не лучший вариант, но вы можете получить элемент из массива внутри коллекции

$collection->all()[0] 
person tylik    schedule 09.11.2018