For-each
Likely you've written a number of for loops to process an array or some other iterable collection. Your loops have looked something like one of these two pseudocode loops:
for each item in items
process item
for i in 0 to items.size
process items[i]
Across the many situations where you have used these loops, the only part that changes is how each individual element is processed. Sometimes an item is printed. Sometimes its memory is freed. Sometimes it is reset. All of these different tasks are subsumed by a single, higher-order for-each function that factors out the loop and leaves the processing as a parametric hole:
class Collection
items = ...
function forEach(processOne)
for i in 0 to items.size
processOne(items[i], i)
Once this forEach
function exists, you no longer need to write loops yourself. Instead you just defer to forEach
, passing a processing function that serves as the loop body:
items.forEach(print)
files.forEach(delete)
messages.forEach(send)
Most Ruby collections support the for-each pattern through their each
method. This script creates an array and processes it in two different ways using blocks:
trees = %w{oak birch walnut}
trees.each { |tree| puts tree.upcase }
trees.each { |tree| tree.reverse! }
If an index is needed by the processing block, the each_with_index
method is used instead. It passes the index as a second parameter to the block:
trees.each_with_index { |tree, i| puts "#{i} -> #{tree}" }
Ruby does have a for-each loop that can be used instead of a higher-order function:
for tree in trees
puts tree
end
However, the Ruby community favors each
and each_with_index
. This runs counter to the Python and JavaScript communities, who tend to favor their builtin for-each loops. That's okay. The communities don't have to all be the same.
The for-each pattern is used to achieve side effects, like printing and mutating. If you want to produce a new value, then you will use a different pattern, like map, filter, or fold.