В мире программирования на Ruby универсальный метод select — больше, чем просто базовый инструмент для фильтрации массивов.
Многие ограничиваются простыми способами его применения, но имеются и продвинутые, цель которых — решение сложных задач, манипулирование данными, удобный для восприятия код.
С пониманием всего потенциала select код Ruby пишется эффективнее и новичками, и профи.
В блоке select с массивом внутри оценивается, истинно условие или ложно, выдается новый, удовлетворяющий условию массив.
Типичное применение метода select — выбор нечетных чисел числового массива.
Пример 1:
[1, 2, 3, 4, 5, 6].select { |n| n.odd? }
=> [1, 3, 5]
Методом to_proc сокращаем этот код.
Пример 2:
[1, 2, 3, 4, 5, 6].select(&:odd?)
=> [1, 3, 5]
Продвинутые варианты применения
Метод «select!»
Это один из методов с восклицательным знаком для фильтрации массива на месте: вместо выдачи нового массива здесь меняется исходный.
Пример 3:
first_array = [1, 2, 3, 4, 5, 6]
first_array.select!(&:odd?)
=> [1, 3, 5]
first_array
=> [1, 3, 5]
second_array = %w[ruby python java rust elixir]
second_array.select!{ |programming_language| programming_language.start_with?('r') }
=> ["ruby", "rust"]
second_array
=> ["ruby", "rust"]
«Select» с другими методами
Select комбинируется и объединяется с другими методами Enumerable, таким как with_index, которым для условия select используются значение массива и индекс значения.
Пример 4:
third_array = %w[ruby python java rust elixir]
third_array.select.with_index { |programming_language, index| programming_language.start_with?('r') && index.even? }
=> ["ruby"]
Сложные условия выбора в блоке «select»
А как быть со сложным набором условий? Например, надо выбрать из массива объект, в котором одно из полей не nil и проверить, не старше ли часа временна́я метка updated_at.
Ради простоты примера взяты только два условия. Добавляйте еще, если поместите их всех в одной строке кода: будет, как в примере выше. Если не помещаются или не читаются в одной строке, делайте аналогично примеру ниже.
Пример 5:
# Комбинируется сколько угодно
# условий, как в следующем
# блоке «select».
# [1, 2, 3, 4, 5, 6].select do |n|
# (n.odd? && n == 3) || n.even? || (n % 3).even?
# end
selected_users = User.active.select do |user|
user_full_address = user.get_full_address
# return true/false is not correct
next(false) if user_full_address.blank?
next(user.updated_at < Time.now - 1.hour)
end
Оказывается, next применяется не только для пропуска итерации в цикле, но и для приема значения параметра. Подробнее о next.
В примере выше вместо ключевого слова return нужно next с аргументом true/false. Здесь получается полный адрес пользователя.
В следующей строке проверяется условие: если адрес пуст, с next(false) он не будет выбран.
Вторым условием проверяется, обновлено поле updated_at в последний час или нет. Так получится искомый результат операции select с указанными выше условиями.
Reject — метод, противоположный select. К нему применимы те же идеи.
Читайте также:
- Раскройте потенциал VS Code для программирования на Ruby
- Новичкам на заметку: реализация шаблона Singleton в Ruby
- Разбор методов Ruby
Читайте нас в Telegram, VK и Дзен
Перевод статьи Banura Randika: Advanced uses of ‘select’ in Ruby