Если блок не задан, то просто проверяется значение истинности каждого элемента. Иными словами, неявно добавляется блок
{|x| x }
.
flag1 = list.all? # list не содержит ни одного false или nil.
flag1 = list.any? # list содержит хотя бы одно истинное значение
#
не nil и не false).
8.3.3. Метод partition
Как говорится, «в мире есть два сорта людей: те, что делят людей по сортам, и те, что не делят». Метод
partition
относится не к людям (хотя мы можем представить их в Ruby как объекты), но тоже делит набор на две части.
Если при вызове
partition
задан блок, то он вычисляется для каждого элемента набора. В результате создаются два массива: в первый попадают элементы, для которых блок вернул значение
true
, во второй — все остальные. Метод возвращает массив, двумя элементами которого являются эти массивы.
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_even = nums.partition {|x| x % 2 == 1 }
# [[1,3,5,7,9],[2,3,4,6,8]]
under5 = nums.partition {|x| x < 5 }
# [[1,2,3,4],[5,6,7,8,9]]
squares = nums.partition {|x| Math.sqrt(x).to_i**2 == x }
# [[1,4,9], [2,3,5,6,7,8]]
Если нужно разбить набор больше чем на две группы, придется написать собственный метод. Я назвал его
classify
по аналогии с методом из класса
Set
.
module Enumerable
def classify(&block)
hash = {}
self.each do |x|
result = block.call(x)
(hashfresult] ||= []) << x
end
hash
end
end
nums = [1,2,3,4,5,6,7,8,9]
mod3 = nums.classify {|x| x % 3 }
# { 0=>[3,6,9], 1=>[1,4,7], 2=>[2,5,8] }
words = %w( area arboreal brick estrous clear donor ether filial
До сих пор мы обходили список по одному элементу за раз. Но иногда желательно на каждой итерации анализировать по два, три или более элементов.
Итератор
each_slice
принимает в качестве параметра число n, равное числу просматриваемых на каждой итерации элементов. (Для работы с ним нужна библиотека
enumerator
.) Если не осталось достаточного количества элементов, размер последнего фрагмента будет меньше.
require 'enumerator'
arr = [1,2,3,4,5,6,7,8,9,10]
arr.each_slice(3) do |triple|
puts triple.join(",")
end
#
Выводится:
# 1,2,3
# 4,5,6
# 7,8,9
# 10
Имеется также итератор
each_cons
, который позволяет обходить набор методом «скользящего окна» заданного размера. (Если название кажется вам странным, знайте, что это наследие языка Lisp.) В таком случае фрагменты всегда будут иметь одинаковый размер.
require 'enumerator'
arr = [1,2,3,4,5,6,7,8,9,10]
arr.each_cons(3) do |triple|
puts triple.join(",")
end
# Выводится:
# 1,2,3
# 2,3,4
# 3,4,5
# 4,5,6
# 5,6,7
# 6,7,8
# 7,8,9
# 8,9,10
8.3.5. Преобразование в массив или множество
Каждая перечисляемая структура теоретически может быть тривиально преобразована в массив (методом
to_a
). Например, такое преобразование для хэша дает вложенный массив пар:
hash = {1=>2, 3=>4, 5=>6}
arr = hash.to_a # [[5, 6], [1, 2], [3, 4]]
Синонимом
to_a
является метод
entries
.
Если была затребована библиотека
set
, становится доступен также метод
to_set
. Дополнительная информация о множествах приведена в разделе 9.1.