Перейти к основному содержимому

Получение частей коллекции

Иногда нужен не весь массив, а только его часть: диапазон элементов, несколько первых или последних, куски одинакового размера или скользящее окно из соседей.

Основной инструмент для этого в PHP — array_slice. array_slice($words, $offset, $length) возвращает $length элементов, начиная с индекса $offset. Второе число — это количество элементов, а не конечный индекс. Если $length не указать, срез дойдёт до конца. Отрицательный $offset отсчитывается от конца, а отрицательный $length останавливается за столько элементов до конца.

  • array_slice($s, $i, $n) — $n элементов, начиная с индекса $i
  • array_slice($s, 0, $n) — первые $n элементов
  • array_slice($s, $i) — всё от индекса $i до конца
  • array_slice($s, -$n) — последние $n элементов
  • array_slice($s, 0, -$n) — всё, кроме последних $n элементов

array_slice всегда создаёт новый массив и копирует в него выбранные элементы. Изменение копии не меняет исходный массив, а изменение исходного массива не меняет копию. В некоторых других языках та же операция даёт представление, разделяющее память с исходными данными, — в PHP этого не происходит никогда.

Для кусков одинакового размера в PHP есть вторая готовая функция — array_chunk. Для задач, с которыми ни одна из этих функций не справляется сама, в этом уроке используется цикл for или foreach и одна-две небольшие вспомогательные функции.

Большинство примеров на этой странице работают с одними и теми же данными: словами one two three four five six.


Срез

Срез — это выбор элементов на некоторых заданных позициях.

Для последовательности соседних позиций используйте array_slice: array_slice($words, 1, 3) даёт элементы с индексами 1, 2 и 3. Внимание: 3 — это длина, а не конечный индекс: начинаем с индекса 1 и берём 3 элемента.

array_slice не умеет пропускать элементы. Чтобы взять каждый второй элемент, используйте цикл for с $i += 2. Если позиции вы перечисляете сами, в своём порядке, то array_map по массиву индексов выберет элемент на каждой из них.

Срез диапазона

array_slice($words, 1, 3) начинает с индекса 1 и берёт 3 элемента: слова с индексами 1, 2 и 3. Результат — новый массив, поэтому его изменение не затронуло бы $words. Программа выводит two, three, four.

Prompt
Создайте массив слов one, two, three, four, five, six. С помощью array_slice со смещением 1 и длиной 3 возьмите элементы с индексами 1, 2 и 3. Выведите результат с помощью implode.
Вывод: PHP-скрипт
Slice a range

Срез с шагом

Чтобы взять каждый второй элемент, цикл for с $i += 2 проходит по индексам 0, 2 и 4 и собирает слова. $part[] = ... добавляет элемент в конец массива.

Prompt
Создайте массив слов one, two, three, four, five, six. Используйте цикл for, который идёт от индекса 0 до индекса 4 с шагом 2 и добавляет каждый элемент в новый массив. Выведите результат с помощью implode.
Вывод: PHP-скрипт
Slice with a step

Срез по списку индексов

Позиции 3, 5 и 0 хранятся в массиве чисел. array_map берёт $words[$i] для каждой из них, поэтому результат получается в порядке индексов: four, six, one.

Prompt
Создайте массив слов one, two, three, four, five, six и массив индексов 3, 5, 0. С помощью array_map по индексам соберите слова на этих позициях в том же порядке. Выведите результат с помощью implode.
Вывод: PHP-скрипт
Slice by a list of indices

Take и Drop

Take означает оставить некоторое количество элементов с одного конца. Drop означает отбросить некоторое количество элементов с одного конца и оставить остальное.

В PHP и то и другое — вызовы array_slice. array_slice($words, 0, 3) берёт первые 3 элемента, а array_slice($words, -3) — последние 3, потому что отрицательное смещение отсчитывается от конца. array_slice($words, 1) отбрасывает первый элемент, а array_slice($words, 0, -5) отбрасывает последние 5, потому что отрицательная длина останавливается за столько элементов до конца.

Есть и условные варианты: takeWhile, takeLastWhile, dropWhile и dropLastWhile. Они не считают элементы. Они идут с одного конца и останавливаются на первом элементе, который не удовлетворяет условию. Встроенных версий в PHP нет, поэтому задачу решает небольшая вспомогательная функция с циклом foreach, а варианты с Last просто переворачивают массив с помощью array_reverse, вызывают ту же вспомогательную функцию и переворачивают результат обратно.

Взять первые или последние n элементов

array_slice($words, 0, 3) оставляет первые 3 слова. array_slice($words, -3) оставляет последние 3, потому что отрицательное смещение отсчитывается от конца.

Prompt
Создайте массив слов one, two, three, four, five, six. С помощью array_slice получите первые 3 элемента и последние 3 элемента. Выведите оба результата на отдельных строках с помощью implode.
Вывод: PHP-скрипт
Take the first or last n elements

Отбросить первые или последние n элементов

array_slice($words, 1) пропускает первое слово и оставляет остальные. array_slice($words, 0, -5) останавливается за 5 элементов до конца, поэтому остаётся только one.

Prompt
Создайте массив слов one, two, three, four, five, six. С помощью array_slice получите всё, кроме первого элемента, и всё, кроме последних 5 элементов. Выведите оба результата на отдельных строках с помощью implode.
Вывод: PHP-скрипт
Drop the first or last n elements

Брать, пока выполняется условие

takeWhile оставляет слова с начала, пока не встретит слово, начинающееся на f. str_starts_with() проверяет начало строки. takeLastWhile оставляет слова с конца, пока не встретит three: она переворачивает массив с помощью array_reverse, вызывает takeWhile и переворачивает результат обратно.

Prompt
Напишите вспомогательные функции takeWhile и takeLastWhile, которые принимают массив и функцию-условие. takeWhile оставляет элементы с начала, пока условие выполняется; takeLastWhile делает то же самое с конца: переворачивает массив, вызывает takeWhile и переворачивает результат обратно. Примените их к словам one, two, three, four, five, six: оставляйте с начала, пока слово не начинается с f, и оставляйте с конца, пока слово не равно three. Выведите оба результата.
Вывод: PHP-скрипт
Take while a condition holds

Отбрасывать, пока выполняется условие

dropWhile пропускает трёхбуквенные слова в начале и оставляет всё начиная с three. dropLastWhile пропускает слова с конца, пока они содержат букву i. str_contains() проверяет, содержит ли строка заданный фрагмент текста.

Prompt
Напишите вспомогательные функции dropWhile и dropLastWhile, которые принимают массив и функцию-условие. dropWhile пропускает элементы с начала, пока условие выполняется, и оставляет остальные; dropLastWhile делает то же самое с конца. Примените их к словам one, two, three, four, five, six: пропускайте с начала, пока слово состоит из 3 букв, и пропускайте с конца, пока слово содержит букву i. Выведите оба результата.
Вывод: PHP-скрипт
Drop while a condition holds

Разбиение на части

Разбиение на части — это разрезание массива на куски одинакового размера. Последний кусок может оказаться короче, если элементы не делятся ровно.

В PHP это встроено: array_chunk($numbers, 3) возвращает массив массивов, и короткий последний кусок получается правильным сам по себе. Поскольку результат вложенный, json_encode выводит его так, что каждый кусок стоит в своих скобках: [[0,1,2],[3,4,5],…].

Чтобы сразу обработать каждый кусок, передайте части в array_map: имя встроенной функции, переданное строкой, например 'array_sum', работает не хуже стрелочной функции.

Разбить на части по 3

Числа от 0 до 13 разрезаются на куски по 3 одним вызовом array_chunk. В последнем куске всего 2 элемента: [12,13].

Prompt
Создайте массив чисел от 0 до 13. С помощью array_chunk разбейте его на части по 3 и выведите результат через json_encode.
Вывод: PHP-скрипт
Split into chunks of 3

Просуммировать каждую часть

Те же части, но каждая суммируется встроенной функцией array_sum. Её имя передаётся в array_map строкой. Остаются только суммы: 3, 12, 21, 30, 25.

Prompt
Создайте массив чисел от 0 до 13. Разбейте его на части по 3 с помощью array_chunk, просуммируйте каждую часть, применив array_sum к частям через map, и выведите массив сумм с помощью implode.
Вывод: PHP-скрипт
Sum each chunk

Окна

Окно — это группа соседних элементов. При работе с окнами группа скользит по массиву и собираются все её положения. В отличие от частей, окна перекрываются.

Встроенной функции windowed в PHP нет. Это делает цикл for, который на каждой позиции вызывает array_slice($items, $i, $size), а небольшая вспомогательная функция windowed делает такой код многоразовым. С параметром $step окно сдвигается сразу на несколько позиций. Если $partial равен true, более короткое окно в конце сохраняется, а не отбрасывается.

Окно размера 2 со шагом 1 — то же самое, что объединение каждого элемента со следующим. В PHP array_map с null вместо функции склеивает два массива элемент за элементом: подайте ей массив без последнего элемента и массив без первого — и вы получите пары соседей.

Окна по 3

Окно содержит 3 слова и сдвигается каждый раз на 1 позицию. Цикл останавливается, когда полное окно больше не помещается, поэтому окон получается 3. Результат — массив массивов, выведенный с помощью json_encode.

Prompt
Напишите вспомогательную функцию windowed, которая принимает массив и размер окна и возвращает каждую группу из такого количества соседних элементов, сдвигаясь на одну позицию за раз. Примените её с размером 3 к словам one, two, three, four, five. Выведите результат через json_encode.
Вывод: PHP-скрипт
Windows of 3

Окна с шагом и неполные окна

Окно содержит 3 числа и сдвигается каждый раз на 2 позиции. Так как $partial равен true, последнее окно [9,10] сохраняется, хотя оно короткое.

Prompt
Напишите вспомогательную функцию windowed, которая принимает массив, размер окна, шаг и флаг partial. Она сдвигается между окнами на step позиций, а когда partial равен true, оставляет также более короткое окно в конце. Примените её к числам от 1 до 10 с размером 3, шагом 2 и partial, равным true. Выведите результат через json_encode.
Вывод: PHP-скрипт
Windows with a step and partial windows

Просуммировать каждое окно

Каждое окно из 3 соседей вырезается с помощью array_slice и суммируется с помощью array_sum. Остаются только суммы: 6, 9, 12.

Prompt
Создайте массив чисел от 1 до 5. Пройдите по каждому окну из 3 соседних элементов, просуммируйте каждое окно с помощью array_sum и соберите суммы. Выведите массив сумм с помощью implode.
Вывод: PHP-скрипт
Sum each window

Объединить каждый элемент со следующим

array_map(null, ...) объединяет каждое слово с его соседом: в первом массиве-аргументе нет последнего элемента, во втором — первого, поэтому массивы выстраиваются как соседи. Второй цикл сравнивает те же пары соседей и записывает, длиннее ли первое слово второго; json_encode выводит логические значения как true и false.

Prompt
Создайте массив слов one, two, three, four, five. Соедините каждый элемент со следующим за ним с помощью array_map с null по массиву без последнего элемента и массиву без первого элемента и выведите массив пар через json_encode. Затем пройдите по тем же соседям и запишите, длиннее ли первое слово второго. Выведите массив логических значений через json_encode.
Вывод: PHP-скрипт
Pair each element with the next one