// std.iter — functional helpers on arrays.
//
// Array-in, array-out. No lazy iterator protocol in v1 — if you
// care about the allocation, use a hand-written `for` loop.
// Every helper handles empty arrays gracefully and preserves
// relative element order.
// Apply `f` to each element; return a new array of results.
// `map([1, 2, 3], fn(x) { return x * 2 })` → `[2, 4, 6]`.
fn map(arr, f) {
let out = []
for x in arr { out.push(f(x)) }
return out
}
// Keep only the elements for which `pred(x)` is truthy.
fn filter(arr, pred) {
let out = []
for x in arr {
if pred(x) { out.push(x) }
}
return out
}
// Fold over the array left-to-right with a two-arg combiner.
// `reduce([1, 2, 3], 0, fn(acc, x) { return acc + x })` → `6`.
fn reduce(arr, initial, combine) {
let acc = initial
for x in arr { acc = combine(acc, x) }
return acc
}
// First `n` elements (or the whole array if it's shorter).
// Negative `n` yields an empty array.
fn take(arr, n) {
if n <= 0 { return [] }
let out = []
let i = 0
for x in arr {
if i >= n { return out }
out.push(x)
i = i + 1
}
return out
}
// Drop the first `n` elements. Negative `n` yields a full
// copy; `n >= arr.len()` yields an empty array.
fn drop(arr, n) {
if n <= 0 { return arr + [] }
let out = []
let i = 0
for x in arr {
if i >= n { out.push(x) }
i = i + 1
}
return out
}
// Pair elements from two arrays. Stops at the shorter array's
// length. `zip([1, 2], ["a", "b"])` → `[[1, "a"], [2, "b"]]`.
fn zip(a, b) {
let out = []
let n = a.len()
let m = b.len()
let k = if n < m { n } else { m }
let i = 0
while i < k {
out.push([a[i], b[i]])
i = i + 1
}
return out
}
// Pair each element with its 0-based index.
// `enumerate(["a", "b"])` → `[[0, "a"], [1, "b"]]`.
fn enumerate(arr) {
let out = []
let i = 0
for x in arr {
out.push([i, x])
i = i + 1
}
return out
}
// `true` if `pred(x)` is truthy for every `x` (and for an empty
// array, by vacuous convention).
fn all(arr, pred) {
for x in arr {
if !pred(x) { return false }
}
return true
}
// `true` if `pred(x)` is truthy for at least one `x`.
fn any(arr, pred) {
for x in arr {
if pred(x) { return true }
}
return false
}
// Count elements for which `pred(x)` is truthy.
fn count(arr, pred) {
let c = 0
for x in arr {
if pred(x) { c = c + 1 }
}
return c
}
// First element for which `pred(x)` is truthy, or `none` if no
// match. Caller is expected to pattern-match / null-check.
fn find(arr, pred) {
for x in arr {
if pred(x) { return x }
}
return none
}
// Index of the first matching element, or `-1` if no match.
fn find_index(arr, pred) {
let i = 0
for x in arr {
if pred(x) { return i }
i = i + 1
}
return -1
}
// Flatten an array of arrays one level down.
// `flatten([[1, 2], [3, 4]])` → `[1, 2, 3, 4]`.
fn flatten(arr) {
let out = []
for inner in arr {
for x in inner { out.push(x) }
}
return out
}
// Sum of a numeric array. Empty → 0.
fn sum(arr) {
let s = 0
for x in arr { s = s + x }
return s
}
// Product of a numeric array. Empty → 1 (multiplicative
// identity; matches NumPy / Python's `math.prod`).
fn product(arr) {
let p = 1
for x in arr { p = p * x }
return p
}
// Min / max of a numeric array. Raises on empty input via a
// deliberate type error so callers notice.
fn min_array(arr) {
let n = arr.len()
if n == 0 { return none[0] }
let m = arr[0]
let i = 1
while i < n {
if arr[i] < m { m = arr[i] }
i = i + 1
}
return m
}
fn max_array(arr) {
let n = arr.len()
if n == 0 { return none[0] }
let m = arr[0]
let i = 1
while i < n {
if arr[i] > m { m = arr[i] }
i = i + 1
}
return m
}