I converted a Ruby method into Crystal, but it’s soooo inelegant compared to the Ruby version. Can some suggest a more Crystal elegant way to do it.
Ruby code
def zeckendorf
return to_enum(__method__) unless block_given?
x = 0
loop do
bin = x.to_s(2)
yield bin unless bin.include?("11")
x += 1
end
end
zeckendorf.take(21).each_with_index{|x,i| puts "%3d: %8s"% [i, x]}
My functional, but inelegant, Crystal translatioin.
def zeckendorf
#return to_enum(__method__) unless block?
x = 0
i = 0 # added
loop do
bin = x.to_s(2)
#yield bin unless bin.includes?("11")
yield bin, i += 1 unless bin.includes?("11")
x += 1
end
end
#zeckendorf.take(21).each_with_index{|x,i| puts "%3d: %8s"% [i, x]}
zeckendorf{ |num, i| puts "%3d: %8s"% [i, num]; (break if i > 20) }
Here’s how the stdlib does this kind of thing. A method that yields and another that returns an iterator:
def zeckendorf
x = 0
loop do
bin = x.to_s(2)
yield bin unless bin.includes?("11")
x += 1
end
end
class ZeckendorfIterator
include Iterator(String)
def initialize
@x = 0
end
def next
bin = @x.to_s(2)
@x += 1
while bin.includes?("11")
bin = @x.to_s(2)
@x += 1
end
bin
end
end
def zeckendorf
ZeckendorfIterator.new
end
zeckendorf.first(21).each_with_index{|x,i| puts "%3d: %8s"% [i, x]}
Thank you @Exilor this is exactly what I was looking for.
Now I just have to remember what to do going forward.
class ZeckendorfIterator
include Iterator(String)
def initialize
@x = 0
end
def next
bin = @x.to_s(2)
@x += 1
while bin.includes?("11")
bin = @x.to_s(2)
@x += 1
end
bin
end
end
def zeckendorf(n)
ZeckendorfIterator.new.first(n)
end
zeckendorf(21).each_with_index{|x,i| puts "%3d: %8s"% [i, x]}