Foreach
For loops allow to iterate over different sets of data and perform actions based on them.
// read a file with numbers in it (file content will always be represented by strings)
// .lines() splits the lines of the file into an array
input = open("examples/aoc/2021/day-1/input").lines()
// define temporary array
a = []
foreach i, number in input
// read each line into temporary array and cast it into an integer
a.push(number.strip().to_i())
end
// assign temporary array to input array
input = a
Return Value​
Loops evaluate to nil, whether they run to completion or exit early through
break.
def iterate(items)
foreach item in items
puts(item)
end
end
a = [1, 2, 3, 4, 5]
b = iterate(a)
// b is nil
Build up a value explicitly if you need one out of a loop:
def doubled(items)
result = []
foreach item in items
result.push(item * 2)
end
return result
end
Until 0.24, foreach returned the value it was iterating, so b above was
[1, 2, 3, 4, 5] — the same array that went in. That did not hold once the
loop hit a break, which produced nil instead, and while never returned
anything but nil.
Scope of the loop variable​
The loop variable is created in the loop's own scope, so it does not exist after the loop finishes:
foreach j in [1, 2, 3]
end
puts(j) // ERROR: identifier not found: j
If a variable of that name already exists outside the loop, though, the loop assigns to that variable rather than creating a new one, and it keeps the last value the loop gave it:
i = 100
foreach i in [1, 2, 3]
end
puts(i) // 3, not 100
This follows from how assignment works generally: assigning to a name that already exists further out updates it in place instead of shadowing it. Use a loop variable name that is not already taken if you need to keep the outer value.
Using an integer​
Count form zero to a given number (excluding):
🚀 > foreach i in 5
puts(i)
end
0
1
2
3
4
=> 5
Using a string​
Iterate over a string:
🚀 > foreach i in "test"
puts(i)
end
"t"
"e"
"s"
"t"
=> "test"
Using break and next​
It is possible to use next or break inside a loop.
foreach i in 5
if (i == 2)
next
end
puts(i)
end
foreach i in 5
if (i == 2)
break
end
puts(i)
end
// Returns
0
1
3
4
0
1
nil
Using range​
You can use the so called rocket range operator to create an individual range with optional stepping:
foreach i in 0 -> 5
puts(i)
end
// outputs
0
1
2
3
4
There is also an inclusive alternative:
foreach i in 0 => 5
puts(i)
end
// outputs
0
1
2
3
4
5
Stepping​
You can specify stepping to change the default of 1
foreach i in 0 -> 5 ^ 2
puts(i)
end
// outputs
0
2
4
Reverse​
Ranges do support going from a higher value to a lower one
foreach i in 5 -> 0 ^ 2
puts(i)
end
// outputs
5
3
1