Reputation: 2103
I stumbled upon such example:
file = "./path"
var = Enumerator.new do |y|
CSV.foreach(file) do |row|
y.yield(row)
end
end
Question is, why store data of any kind, inside enumerators, insted of arrays? what is the difference in behaviour between whats above and this:
file = "./path"
var = []
CSV.foreach(file) do |row|
var << row
end
when i want to something with the data it looks the same for both cases:
var.each {|row| puts row}
So what are the advantages and disadvantages of such constructions?
Upvotes: 1
Views: 108
Reputation: 10304
In general, iterators can be used to lazily generate a sequence of objects. This is the main advantage when creating a lazy enumeration compared to creating a collection of items which is much more efficient.
For example, if your enumerator loop iterates over just the first 5 items of 3 million items then that's all yield returns, and you didn't build up a collection of 1 million items internally first.
So, you do not need to load all the 3 millions items just for your callee function can continue and executes the rest of the code.
Iterators are means for returning sequences.
Sometimes The sequence might even be infinite.
It brings the functional programming concept of lazy evaluation to Ruby – at least for enumerations.
There is a huge difference between returning a collection and returning a collection generator.
Upvotes: 4
Reputation: 7675
Too see the difference of the code add a puts
within the loops.
seq = (1..3)
enum = Enumerator.new do |y|
seq.each do |i|
puts "Grabbing #{i} with enumerator"
y.yield(i)
end
end
enum.each { |i| puts "Taken #{i} from enumerator" }
# Grabbing 1 with enumerator
# Taken 1 from enumerator
# Grabbing 2 with enumerator
# Taken 2 from enumerator
# Grabbing 3 with enumerator
# Taken 3 from enumerator
array = []
seq.each do |i|
puts "Grabbing #{i} with array"
array << i
end
array.each { |i| puts "Taken #{i} from array" }
# Grabbing 1 with array
# Grabbing 2 with array
# Grabbing 3 with array
# Taken 1 from array
# Taken 2 from array
# Taken 3 from array
Like mentioned by Tal Avissar the Enumerator
fetches the value when it's needed which is called lazy evaluation. This behavoir is a benefit in some situations.
# infinite number sequence
numbers = Enumerator.new do |y|
n = 0
loop { y.yield(n += 1) }
end
puts numbers.take(3).join(', ')
# 1, 2, 3
When dealing with huge or infinite sequences the difference is quite important.
Upvotes: 0