Range Over Iterators in Crystal
Our first program will explore iterating over data and returning an iterator. This lets us range over pretty much anything in the data structure! Here’s the full source code.
class List(T)
struct Element
property next : Element?
property val : T
end
property head : Element?
property tail : Element?
def push(v : T)
new_element = Element.new(val: v)
if @tail.nil?
@head = new_element
@tail = new_element
else
@tail.not_nil!.next = new_element
@tail = new_element
end
end
def all
Iterator(T).new do |yield|
element = @head
while element
break unless yield.call(element.val)
element = element.next
end
end.to_a
end
end
class Iterator(T)
def initialize(&block : Proc(T, Bool)::)->Nil)
@block = block
end
def each(&block : (T ->))
@block.call do |value|
block.call(value)
true
end
end
def to_a : Array(T)
array = [] of T
each do |element|
array << element
end
array
end
end
def gen_fib
Iterator(Int32).new do |yield|
a = 1
b = 1
loop do
break unless yield.call(a)
a, b = b, a + b
end
end
end
list = List(Int32).new
list.push(10)
list.push(13)
list.push(23)
list_all = list.all
puts "List Elements:"
list_all.each do |e|
puts e
end
fib_iterator = gen_fib
fib_iterator.each do |n|
break if n >= 10
puts n
end
puts "Collected Fib:"
puts fib_iterator.to_a.inspect
In this example, we define a List
class in Crystal that can store elements. The all
method in the List
class returns an iterator. This iterator can be used in a loop to range over all the elements of the list.
We also create a gen_fib
function, which returns an iterator over Fibonacci numbers. This keeps running as long as the yield
keeps returning true
.
To add elements to the list, we create an instance of List
and use the push
method. We then range over the list using the returned iterator from the all
method.
Lastly, we generate and print Fibonacci numbers using the gen_fib
function.
This example illustrates the power and flexibility of iterators in Crystal, making it easy to range over custom data structures and implement complex iteration logic seamlessly.