Массивы и их методы
Массив — это упорядоченный список значений. Это самая универсальная коллекция Ruby, и у неё десятки готовых методов на любой случай.
Суть: массив (Array) хранит элементы по порядку с доступом по индексу (с нуля); он динамический (растёт и сжимается) и может содержать значения любых типов вперемешку.
Массивы в Ruby невероятно гибкие. Они не требуют фиксированного размера и типа: в одном массиве могут лежать число, строка и даже другой массив. Доступ к элементам — по индексу, начиная с нуля, причём отрицательные индексы считают с конца.
nums = [10, 20, 30, 40]
puts nums[0] # => 10 (первый)
puts nums[-1] # => 40 (последний)
puts nums.first(2).inspect # => [10, 20]
puts nums.length # => 4
nums << 50 # добавить в конец (push)
nums.unshift(5) # добавить в начало
puts nums.inspect # => [5, 10, 20, 30, 40, 50]
Разбор: добавление, удаление, срезы
Оператор << («shovel», лопата) добавляет элемент в конец — это самый частый способ. Для удаления есть pop (с конца), shift (с начала), delete (по значению). Срезы достаются диапазоном индексов.
letters = ["a", "b", "c", "d", "e"]
puts letters[1..3].inspect # => ["b", "c", "d"] срез
puts letters[1, 2].inspect # => ["b", "c"] старт + длина
last = letters.pop # удалить и вернуть последний => "e"
letters.delete("a") # удалить по значению
puts letters.inspect # => ["b", "c", "d"]
Как работает под капотом
Массив Ruby хранит ссылки на объекты в непрерывном блоке памяти. Доступ по индексу мгновенный — Ruby сразу знает, где лежит N-й элемент. Добавление в конец почти всегда быстрое, а вот вставка в начало (unshift) дороже, потому что приходится сдвигать остальные элементы.
индексы: 0 1 2 3
+-----+-----+-----+-----+
nums = | 10 | 20 | 30 | 40 |
+-----+-----+-----+-----+
индексы: -4 -3 -2 -1 <-- отрицательные с конца
nums << 50 добавляет справа --> [10,20,30,40,50]
nums.shift убирает слева --> [20,30,40]
Частые ошибки
- Выход за границы. Обращение к несуществующему индексу
nums[99]возвращаетnil, а не ошибку — и это коварно, ошибка всплывёт позже. - Путать [] и метод.
nums[1,2]— это «старт, длина», аnums[1..2]— диапазон. Лёгко перепутать. - Изменять массив во время перебора. Удаление элементов прямо в
eachломает обход — собирайте результат в новый массив.
Best practices
- Для добавления в конец предпочитайте
<<— это идиоматично и читаемо. - Создавайте массив фиксированных значений быстро через
%w[a b c](массив слов) вместо кавычек и запятых. - Используйте
.digдля безопасного доступа к вложенным массивам:data.dig(0, 1)не упадёт наnil.
Глубже: массивы как универсальный инструмент
Массив в Ruby настолько богат методами, что значительная часть повседневных задач решается одной их комбинацией без единого явного цикла. Нужно убрать дубликаты — uniq. Перевернуть — reverse. Перемешать — shuffle. Сгруппировать по N штук — each_slice. Разбить по условию — partition. Сплющить вложенность — flatten. Найти первый подходящий — find. Эта плотность методов не случайна: массив реализует модуль Enumerable, о котором речь пойдёт отдельно, и потому наследует десятки операций перебора и преобразования. Практический вывод для новичка: прежде чем писать цикл вручную, спросите себя — нет ли уже готового метода? В девяти случаях из десяти он есть, и код с ним будет короче, читаемее и быстрее (многие методы реализованы на C). Полезная привычка — держать под рукой документацию класса Array и периодически её листать: каждый новый освоенный метод убирает из вашего кода ещё один ручной цикл и ещё одну возможность ошибиться.
Итог. Массив — упорядоченная динамическая коллекция с доступом по индексу с нуля и отрицательными индексами с конца. Добавление в конец дёшево, в начало — дороже; обращение за границы даёт nil, а не ошибку.