a.each_with_object({}) { |(kout, kin, val), h| (h[kout] ||= []) << { kin => val } }
#=> {"4"=>[{"dog"=>"woof"}, {"cow"=>"moo"}], "2"=>[{"man"=>"yo"}, {"yeti"=>"wrarghh"}]}
У нас есть
enum = a.each_with_object({})
#=> #<Enumerator: [["4", "dog", "woof"], ["4", "cow", "moo"], ["2", "man", "yo"],
# ["2", "yeti", "wrarghh"]]:each_with_object({})>
Первое значение генерируется этим перечислителем и передается в блок, а переменным блока присваиваются значения:
(kout, kin, val), h = enum.next
#=> [["4", "dog", "woof"], {}]
, который разлагается следующим образом.
kout
#=> "4"
kin
#=> "dog"
val
#=> "woof"
h #=> {}
Таким образом, расчет блока равен
(h[kout] ||= []) << { kin => val }
#=> (h[kout] = h[kout] || []) << { "dog" => "wolf" }
#=> (h["4"] = h["4"] || []) << { "dog" => "wolf" }
#=> (h["4"] = nil ||= []) << { "dog" => "wolf" }
#=> (h["4"] = []) << { "dog" => "wolf" }
#=> [] << { "dog" => "wolf" }
#=> [{ "dog" => "wolf" }]
h["4"] || [] #=> []
, поскольку h
не имеет ключа "4"
и, следовательно, h["4"] #=> nil
.
Следующее значение enum
передается в блок, и вычисления повторяются.
(kout, kin, val), h = enum.next
#=> [["4", "cow", "moo"], {"4"=>[{"dog"=>"woof"}]}]
kout
#=> "4"
kin
#=> "cow"
val
#=> "moo"
h #=> {"4"=>[{"dog"=>"woof"}]}
(h[kout] ||= []) << { kin => val }
#=> (h[kout] = h[kout] || []) << { "cow" => "moo" }
#=> (h["4"] = h["4"] || []) << { "cow" => "moo" }
#=> (h["4"] = [{"dog"=>"woof"}] ||= []) << { "cow" => "moo" }
#=> (h["4"] = [{"dog"=>"woof"}]) << { "cow" => "moo" }
#=> [{"dog"=>"woof"}] << { "cow" => "moo" }
#=> [{ "dog" => "wolf" }, { "cow" => "moo" }]
На этот раз h["4"] || [] #=> [{ "dog" => "wolf" }]
, поскольку h
теперь имеет ключ "4"
с истинным значением ([{ "dog" => "wolf" }]
).
Остальные расчеты аналогичны.