letters.each do |a,b,*rest|
puts rest.each_with_object([a+b]) { |s,arr| arr << arr.first + s }.join(' ')
end
печатает
AB
CD CDF CDG
HI HIJ
Шаги следующие.
Предположим,
letters = [["C", "D", "F", "G"],["H", "I", "J" ]]
Затем
enum0 = letters.each
#=> #<Enumerator: [["C", "D", "F", "G"], ["H", "I", "J"]]:each>
Первыйэлемент этого перечислителя генерируется и передается в блок, а трем переменным блока присваиваются значения.
a, b, *rest = enum0.next
#=> ["C", "D", "F", "G"]
a
#=> "C"
b
#=> "D"
rest
#=> ["F", "G"]
Далее получаем
enum1 = rest.each_with_object([a+b])
#=> rest.each_with_object(["CD"])
#=> #<Enumerator: ["F", "G"]:each_with_object(["CD"])>
Первый элемент этого перечислителягенерируется и передается в блок, а переменным блока присваиваются значения.
s, arr = enum1.next
#=> ["F", ["CD"]]
s
#=> "F"
arr
#=> ["CD"]
Теперь выполняется вычисление блока.
arr << arr.first + s
#=> arr << "CD" + "F"
#=> ["CD", "CDF"]
Второй и последний элемент enum1
- этогенерируется и передается в блок, а переменным блока присваиваются значения, и блок вычисляется.
s, arr = enum1.next
#=> ["G", ["CD", "CDF"]]
arr << arr.first + s
#=> ["CD", "CDF", "CDG"]
При попытке сгенерировать другой элемент из enum1
мы получаем
enum1.next
#StopIteration: iteration reached an end
Ruby обрабатывает исключение, разбивая блок и возвращая arr
.Затем элементы arr
объединяются:
arr.join(' ')
#=> "CD CDF CDG"
и печатаются.
Второй и последний элемент enum0
теперь генерируется, передается в блок и в три блокапеременным присваиваются значения.
a, b, *rest = enum0.next
#=> ["H", "I", "J"]
a
#=> "H"
b
#=> "I"
rest
#=> ["J"]
Остальные вычисления аналогичны.
Некоторые читатели могут быть незнакомы с методом Enumerable # each_with_object , который широко используется.Прочитайте документ, но обратите внимание, что здесь он дает тот же результат, что и код, написанный следующим образом.
letters.each do |a,b,*rest|
arr = [a+b]
rest.each { |s| arr << arr.first + s }
puts arr.join(' ')
end
Используя each_with_object
, мы избегаем необходимости в операторе arr = [a+b]
и операторе puts arr.join(' ')
,Функции этих двух операторов, конечно, присутствуют в строке, используя each_with_object
, но большинство пользователей Ruby предпочитают поток, когда цепочка each_with_object
- join(' ')
.Еще одно отличие состоит в том, что значение arr
ограничено блоком each_with_object
, что является хорошей практикой программирования.