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

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

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

В других языках у списков есть методы вроде slice, take, drop, chunked и windowed. В Go таких методов нет. Вместо них в Go есть выражение среза: s[low:high] даёт элементы с индекса low до индекса high, не включая его. Опустите low, чтобы начать с начала, или опустите high, чтобы дойти до конца.

Выражение среза ничего не копирует. Новый срез разделяет память с исходным. Если вы измените элемент в части, изменится и оригинал. Когда нужна независимая копия, используйте slices.Clone() из пакета slices.

Для задач, которые выражение среза не может решить само по себе, в этом уроке используются цикл for, пакет slices или небольшая обобщённая вспомогательная функция.

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

Синтаксис выражения среза

Три самые распространённые формы. n — это количество или индекс. Конечный индекс никогда не включается.

main.go
s[low:high]   // elements from index low up to, but not including, high
s[:n]         // the first n elements
s[n:]         // everything from index n to the end

Срез (slice)

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

Для непрерывного ряда соседних позиций используйте выражение среза: words[1:4] даёт элементы с индексами 1, 2 и 3. Помните, что конечный индекс не включается: чтобы получить элементы с индексами от 1 до 3, вы пишете 1:4.

Выражение среза не может пропускать элементы. Чтобы взять каждый второй элемент или элементы на позициях, которые вы перечисляете сами, используйте цикл for и append() для добавления каждого выбранного элемента в новый срез.

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

words[1:4] начинается с индекса 1 и останавливается перед индексом 4. В результате получается 3 элемента.

Prompt
Создайте срез из слов one, two, three, four, five, six. С помощью выражения среза возьмите элементы с индекса 1 до индекса 4, не включая его. Выведите результат.
Вывод: программа на Go и захваченный вывод
Slice a range

Срез с шагом

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

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

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

Позиции 3, 5 и 0 хранятся в срезе типа int. Цикл выбирает слово на каждой позиции, поэтому результат получается в порядке индексов.

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

Take и Drop

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

В Go и то и другое — это выражения среза. words[:3] берёт первые 3 элемента, а words[len(words)-3:] берёт последние 3. words[1:] отбрасывает первый элемент, а words[:len(words)-5] отбрасывает последние 5.

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

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

words[:3] оставляет первые 3 слова. words[len(words)-3:] оставляет последние 3.

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

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

words[1:] пропускает первое слово. words[:len(words)-5] пропускает последние 5 слов, поэтому остаётся только one.

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

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

TakeWhile оставляет слова с начала, пока не встретит слово, начинающееся с f. TakeLastWhile оставляет слова с конца, пока не встретит three. strings.HasPrefix() проверяет начало строки.

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

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

DropWhile пропускает слова из 3 букв в начале и оставляет всё, начиная с three. DropLastWhile пропускает слова с конца, пока они содержат букву i. strings.Contains() проверяет, содержит ли строка кусок текста.

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

Chunked (разбиение на части)

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

В Go это встроено начиная с версии 1.23: slices.Chunk(s, n). Она возвращает не срез срезов напрямую, а итератор, который выдаёт вам части одну за другой в цикле for range. Используйте slices.Collect(), чтобы собрать все части в [][]int.

Чтобы обработать каждую часть сразу же, пройдите циклом по частям и выполните работу внутри цикла.

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

Числа от 0 до 13 разрезаются на куски по 3. В последнем куске всего 2 элемента.

Prompt
Создайте срез из чисел от 0 до 13. С помощью slices.Chunk разбейте его на части по 3 элемента, а с помощью slices.Collect соберите части в срез срезов. Выведите результат.
Вывод: программа на Go и захваченный вывод
Split into chunks of 3

Сумма каждой части

Те же самые части, но каждая складывается внутри цикла. Сохраняются только суммы.

Prompt
Создайте срез из чисел от 0 до 13. Пройдите циклом по slices.Chunk с размером части 3, сложите числа в каждой части и добавьте сумму в новый срез. Выведите срез сумм.
Вывод: программа на Go и захваченный вывод
Sum each chunk

Windowed (скользящее окно)

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

Встроенного windowed в Go нет. Это делает цикл for с выражением среза items[i:i+size]. Небольшая обобщённая вспомогательная функция Windowed делает такой код переиспользуемым. С параметром step окно сдвигается сразу на несколько позиций. Если partial равен true, короткое окно в конце сохраняется, а не отбрасывается.

Окно из 2 элементов, которое сдвигается на 1 шаг, — это то же самое, что соединить каждый элемент со следующим. В Go это цикл, который останавливается за один элемент до конца.

Окна по 3 элемента

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

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

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

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

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

Сумма каждого окна

Каждое окно из 3 соседних элементов складывается. Сохраняются только суммы.

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

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

Первый цикл строит Pair из каждого слова и его соседа. Второй цикл сравнивает тех же соседей и записывает, длиннее ли первое слово, чем второе.

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