Перечислимые объекты - это модули в Ruby, которые предоставляют очень разнообразный набор методов, которые в основном используются для просмотра, сортировки или управления коллекциями. Перечисления возможны благодаря концепции миксинов в Ruby, которая позволяет включать модули в класс, а класс имеет доступ к методам модуля. Это мощная концепция, которая позволяет «унаследовать» функциональные возможности из нескольких мест и разделить их между несвязанными классами, уменьшая необходимость переписывать код между классами.
Можно узнать, какие классы используют Enumerable с Object#included_modules
.
>> Array.included_modules => [Enumerable, Kernel] >> String.included_modules => [Comparable, Kernel]
Обратите внимание, что класс String не включает модуль Enumerable. Это связано с тем, что для того, чтобы класс мог использовать модуль Enumerable, он должен предоставить свой собственный метод #each
, чтобы преобразовать последовательные элементы в коллекции в блок.
Метод #each
- это простой и отличный метод для итерации по коллекции, передавая каждый элемент объекта в указанный блок.
> ['cat', 'dog', 'bird'].each {|el| puts el.upcase} CAT DOG BIRD => ["cat", "dog", "bird"]
Однако, поскольку возвращаемое значение метода #each
- это исходная коллекция, для возврата измененной коллекции потребуются дополнительные строки кода. К счастью для нас, существует множество других перечислимых методов, которые обеспечивают дополнительную функциональность и могут сохранять наш код кратким и чистым!
1. #map
#map
возвращает новый массив, заполненный результатами однократного запуска блока для каждого элемента в коллекции. Это уменьшает необходимость вручную создавать массив результатов, как это было бы, если бы мы использовали #each
enumerable.
>['cat', 'dog', 'bird'].map {|el| el.upcase} =>["CAT", "DOG", "BIRD"]
2. #select
or #reject
#select
возвращает новую коллекцию, содержащую все элементы в своем приемнике, для которых данный блок возвращает истинное значение.
И наоборот, #reject
возвращает новую коллекцию, содержащую все элементы в своем приемнике, для которых данный блок возвращает ложное значение.
>[1,2,3,4].select {|x| x.odd?} =>[1, 3] >[1,2,3,4].reject {|x| x.odd?} =>[2,4]
3. #count
Метод #count
можно использовать тремя способами.
Во-первых, без аргументов его можно использовать как синоним длины.
>[1,2,3,4,5].count => 5
Во-вторых, с одним аргументом вернет количество элементов, равное данному аргументу.
>[1,2,3,4,5].count(2) => 1
И в-третьих, для данного блока будет возвращено количество элементов, которые при передаче в данный блок вернут истинное значение.
>[1,2,3,4,5].count {|int| int.odd?} => 3
4. #reduce или #inject
Метод #reduce
или #inject
работает как агрегатор, объединяя все элементы своего получателя, применяя бинарную операцию, и может быть вызван тремя способами.
Во-первых, с одним аргументом:
>[1,2,3].reduce(:+) => 6
#reduce
принимает символ, который называет двоичный метод или оператор
Во-вторых, с блоком и без аргумента - у блока два параметра: аккумулятор и текущий элемент:
>[1,2,3].reduce {|acc, el| acc + el} => 6
Функционально это эквивалентно предыдущему примеру. Первый элемент в массиве используется как аккумулятор, который затем переназначается после каждой итерации. Однако использование этого блока дает больший контроль над тем, как уменьшить приемник - вы не ограничены двоичными методами / операциями, как в предыдущем примере.
И, наконец, #reduce
может вызываться как с блоком, так и с аргументом:
>[12,2,2].reduce(48) {|acc, el| acc/el} => 1
Интерпретатор сначала назначает аккумулятор данному аргументу, а затем выполняет итерацию по всему получателю, не пропуская первый элемент. В приведенном выше примере шаги оцениваются следующим образом:
48/12 = 4
4/2 = 2
2/2 = 1
В заключении…
Перечисления - это мощный инструмент, который может выполнять сложные операции с относительно небольшим количеством строк кода. Отчасти радость и волнение, которые я испытал с тех пор, как я начал свое путешествие по изучению программирования на Ruby, связан с изучением множества различных перечислимых методов и поиском новых способов подхода и решения проблем.