Iter
UpdatedIter<T>
import { Iter } from "@alloy/std/iter" local players = game:GetService("Players"):GetPlayers() local names = Iter.from(players) :filter(function(p) return p.Team ~= nil end) :map(function(p) return p.Name end) :take(5) :collect() for i in Iter.range(1, 10, 2) do end
A lazy iterator, from the std: each step wraps the last, and nothing runs until collect, for_each, a reducer, or a for loop pulls. Iter.from takes an array, a function that returns the next value or nil, or a Set, Queue, Heap, or HashMap; it keeps the element type, so Iter.from(number[]) is Iter<number> and :collect() is number[]. Another table with an __iter metamethod needs a cast. Iter.range(from, to, step?) counts, inclusive.
map keeps the element type through any number of steps, so every callback in a chain knows its parameter type.
Statics
Iter.from
Iter.from<T>(source: T[] | (() -> T?) | Set<T> | Queue<T> | Heap<T> | HashMap<any, T>): Iter<T>
A lazy iterator over an array, a function that returns the next value or nil, or a std collection. It keeps the element type, so Iter.from(number[]) collects back to number[].
import { Iter } from "@alloy/std/iter" local xs = Iter.from([ 1, 2, 3 ]):collect() print(xs:len())
Iter.range
Iter.range(from: number, to: number, step: number?): Iter<number>
The numbers from from to to, both inclusive, by step. step defaults to 1.
import { Iter } from "@alloy/std/iter" for i in Iter.range(1, 10, 2) do print(i) end
Methods
Iter:next
Iter:next(): T?
Pulls one value, or nil at the end. Every other reader is built on it.
import { Iter } from "@alloy/std/iter" local it = Iter.from([ 1, 2 ]) print(it:next())
Iter:map
Iter:map<U>(f: (T) -> U): Iter<U>
Each value as f(value), still lazily. The result keeps the new element type, however long the chain.
import { Iter } from "@alloy/std/iter" local names = Iter.from([ 1, 2 ]):map(function(n) return `#{n}` end) print(names:collect():join(", "))
Iter:filter
Iter:filter(f: (T) -> boolean): Iter<T>
The values where f(value) holds. Nothing runs until something pulls.
import { Iter } from "@alloy/std/iter" local big = Iter.from([ 1, 5 ]):filter(function(n) return n > 2 end) print(big:count())
Iter:take
Iter:take(n: number): Iter<T>
The first n values, then the end. The source is never pulled past them.
import { Iter } from "@alloy/std/iter" print(Iter.range(1, 100):take(3):count())
Iter:skip
Iter:skip(n: number): Iter<T>
Everything after the first n values.
import { Iter } from "@alloy/std/iter" print(Iter.range(1, 5):skip(3):count())
Iter:take_while
Iter:take_while(f: (T) -> boolean): Iter<T>
Values until f(value) first fails; that value and the rest are dropped.
import { Iter } from "@alloy/std/iter" local it = Iter.range(1, 10):take_while(function(n) return n < 4 end) print(it:count())
Iter:chain
Iter:chain(other: Iter<T>): Iter<T>
This iterator, then other, as one run.
import { Iter } from "@alloy/std/iter" local both = Iter.from([ 1 ]):chain(Iter.from([ 2 ])) print(both:count())
Iter:collect
Iter:collect(): T[]
Pulls every value into an array. This is what ends a chain.
import { Iter } from "@alloy/std/iter" local xs = Iter.range(1, 3):collect() print(xs:join(", "))
Iter:to_table
Iter:to_table(): { T }
The rest of the run, drained into a new table. An Iter holds no table of its own, so this one is a copy, and the pull spends the iterator: a second call gives an empty table.
import { Iter } from "@alloy/std/iter" local t = Iter.range(1, 3):to_table() print(#t)
Iter:for_each
Iter:for_each(f: (T) -> ())
Pulls every value and calls f on it.
import { Iter } from "@alloy/std/iter" Iter.from([ 1, 2 ]):for_each(function(n) print(n) end)
Iter:count
Iter:count(): number
Pulls every value and returns how many there were. It consumes the iterator.
import { Iter } from "@alloy/std/iter" print(Iter.range(1, 5):count())
Iter:any
Iter:any(f: (T) -> boolean): boolean
Whether f holds for some value. It stops at the first hit.
import { Iter } from "@alloy/std/iter" print(Iter.from([ 1, 5 ]):any(function(n) return n > 3 end))
Iter:all
Iter:all(f: (T) -> boolean): boolean
Whether f holds for every value. It stops at the first miss.
import { Iter } from "@alloy/std/iter" print(Iter.from([ 1, 5 ]):all(function(n) return n > 0 end))
Iter:find
Iter:find(f: (T) -> boolean): T?
The first value where f holds, or nil. It stops there, so the rest is never pulled.
import { Iter } from "@alloy/std/iter" print(Iter.range(1, 10):find(function(n) return n % 4 == 0 end))
Iter:reduce
Iter:reduce<U>(f: (U, T) -> U, init: U): U
Folds the run: acc = f(acc, value) from init, and the last acc is the result.
import { Iter } from "@alloy/std/iter" local sum = Iter.range(1, 4):reduce(function(acc: number, n) return acc + n end, 0) print(sum)
Iter:first
Iter:first(): T?
The first value, or nil for an empty run. It pulls once.
import { Iter } from "@alloy/std/iter" print(Iter.from([ 1, 2 ]):first())
Iter:last
Iter:last(): T?
The last value, or nil for an empty run. It pulls the whole run.
import { Iter } from "@alloy/std/iter" print(Iter.from([ 1, 2 ]):last())
