Skip to content
FutureBlitz

    Install

    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].

    shop.fb
    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)
    Output
    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.

    shop.fb
    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 For
    Output
    reorder 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.

    shop.fb
    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 For
    Output
    TEA-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.

    shop.fb
    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)
    Output
    {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.

    shop.fb
    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))
    Output
    27 81

    What you learned

    • For x In values goes over any collection; For i, x In adds an array’s index.
    • A loop variable is a read-only copy; assign values[i] to change an element.
    • For key, value In map takes each entry apart, and For entry In map gives 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 lists Implements Iterable<T>.

    Report an issue with this page or with FutureBlitz on GitHub.