n = 3
arr = ["1", "b", "0", "7", "9", "2", "a", "a", "5", "7"]
arr.each_slice(n).map { |a| n.times.map { |i| a.fetch(i, false) } }
#=> [["1", "b", "0"], ["7", "9", "2"], ["a", "a", "5"], ["7", false, false]]
Шаги следующие.
n = 3
arr = ["1", "b", "0", "7", "9", "2", "a", "a", "5", "7"]
enum0 = arr.each_slice(n)
#=> #<Enumerator: ["1", "b", "0", "7", "9", "2", "a", "a",
# "5", "7"]:each_slice(3)>
enum1 = enum0.map
#=> #<Enumerator: #<Enumerator: ["1", "b", "0", "7", "9", "2", "a",
# "a", "5", "7"]:each_slice(3)>
Используется форма Enumerable # map , в которой нет блока. Посмотрите на возвращаемое значение enum1
. Его можно рассматривать как составной перечислитель , хотя в Ruby такого понятия нет. Примечание:
enum1.each { |a| n.times.map { |i| a.fetch(i, false) } }
#=> [["1", "b", "0"], ["7", "9", "2"], ["a", "a", "5"], ["7", false, false]]
См. Перечислитель # каждый .
Первый элемент enum1
генерируется и передается в блок, а переменной блока a
присваивается его значение:
a = enum1.next
#=> ["1", "b", "0"]
См. Перечислитель # следующий . Расчет блока теперь выполняется:
enum2 = n.times.map
#=> #<Enumerator: #<Enumerator: 3:times>:map>
i = enum2.next
#=> 0
a.fetch(i, false)
#=> ["1", "b", "0"].fetch(0, false)
#=> "1"
i = enum2.next
#=> 1
a.fetch(i, false)
#=> ["1", "b", "0"].fetch(1, false)
#=> "b"
i = enum2.next
#=> 2
a.fetch(i, false)
#=> ["1", "b", "0"].fetch(2, false)
#=> "0"
i = enum2.next
#=> StopIteration (iteration reached an end)
map
поэтому возвращает ["1", "b", "0"]
. Расчеты аналогичны для:
enum1.next
#=> ["7", "9", "2"]
и
enum1.next
#=> ["a", "a", "5"]
Во всех этих случаях мы могли бы использовать a[i]
вместо a.fetch(i, false)
.
Наконец,
a = enum1.next
#=> ["7"]
enum2 = n.times.map
#=> #<Enumerator: #<Enumerator: 3:times>:map>
enum2.each { |i| a.fetch(i, false) }
#=> ["7", false, false]
Как и прежде, enum2
передает 0
, 1
и 2
в блок. В последних двух случаях Array # fetch возвращает свое значение по умолчанию , false
, поскольку индекс выходит за пределы.