Collections, 4 of 6
Iterating with For ... In
Go over arrays, Maps, Sets, ranges, and strings with For ... In, and know what a loop can change.
What you’ll build
A stock report for a small shop: it goes over a list of products, a Map of stock levels, and the
letters of a product code, and flags what needs reordering. For ... In is the one loop for all
of them, and it works the same way over every collection.
Values, and their indexes
For x In values gives each value in turn. Over an array, For i, x In values gives each with
its index too. The loop’s variables are copies that can’t be assigned, so a loop can’t change an
element by mistake; to change one, assign values[i].
Import std.core
Local products = ["tea", "coffee", "cocoa"]
Local prices = [280, 350, 300]
For product In products
Print(product)
End For
For i, price In prices
prices[i] = price + price / 10
End For
Print(prices)tea coffee cocoa [308, 385, 330]
Maps
Over a Map, For key, value In map takes each entry apart. For entry In map gives each entry
whole, as a tuple whose elements are entry.0 and entry.1. A Set gives its values, in the
order they were added.
Import std.core
Import std.collections
Local stock = {"tea": 12, "coffee": 0, "cocoa": 3}
For product, count In stock
If count < 5 Then Print("reorder {product}: {count} left")
End For
For entry In stock
Print(entry)
End Forreorder coffee: 0 left reorder cocoa: 3 left (tea, 12) (coffee, 0) (cocoa, 3)
Ranges and strings
A range is a sequence of numbers, so For i In 1 To 3 is the same as For i = 1 To 3. A
string’s Chars is an array of its characters, and its Bytes an array of its UTF-8 bytes.
Import std.core
Import std.text
Local code = "TEA-0042"
Local digits = 0
For c In code.Chars
If c.IsDigit() Then digits++
End For
Print("{code} has {digits} digits")
For shelf In 1 To 3
Print("shelf {shelf}")
End ForTEA-0042 has 4 digits shelf 1 shelf 2 shelf 3
Changing a collection during a loop
Adding a key to a Map or removing one while a loop goes over it would make the loop skip or repeat entries, so std’s collections panic at the loop’s next step instead. Collect what to change, then change it after the loop.
Import std.core
Import std.collections
Local stock = {"tea": 12, "coffee": 0, "cocoa": 3, "chai": 0}
Local soldOut: String[] = []
For product, count In stock
If count == 0 Then soldOut.Add(product)
End For
For product In soldOut
stock.Remove(product)
End For
Print(stock){tea: 12, cocoa: 3}A Map’s existing key can get a new value during a loop over it, since that changes no entry’s
place. An array doesn’t panic: it reads its Count before each pass, so a value added during the
loop is reached too, and a loop that removes values ends sooner and skips the value after each one
removed. Remove from an array after the loop too.
Any collection
Every collection in std.collections goes in a For ... In, and so does any type with an
Iterate() Method. std’s collections and arrays also implement Iterable<T>, an Interface from
std.core: a promise, which a type makes by listing it, that the type has an Iterate() giving
Ts. So a parameter of type Iterable<Int> takes any of them that holds Ints. The next tutorial
makes a type of your own that goes in a loop and implements Iterable<T>, and
Interfaces covers Interfaces in full.
Import std.core
Import std.collections
Function Total(counts: Iterable<Int>): Int
Local sum = 0
For count In counts
sum += count
End For
Return sum
End Function
Local shelf = [4, 8, 15]
Local store = Set<Int>()
store.AddAll([16, 23, 42])
Print(Total(shelf), Total(store))27 81
What you learned
For x In valuesgoes over any collection;For i, x Inadds an array’s index.- A loop variable is a read-only copy; assign
values[i]to change an element. For key, value In maptakes each entry apart, andFor entry In mapgives tuples.- Adding or removing entries while going over a std collection panics, and removing from an array skips values; change either after the loop.
- An
Iterable<T>parameter takes any of std’s collections, an array, or a type that listsImplements Iterable<T>.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.