Array #

Arrays in Quest are ordered, mutable collections of values that can hold any type. Following Python's design, arrays are mutable - methods like push(), pop(), and sort() modify the array in place.

Array Literals #

let empty = []
let numbers = [1, 2, 3, 4, 5]
let mixed = [1, "hello", true, nil]
let nested = [[1, 2], [3, 4], [5, 6]]

Array Access #

Arrays can be accessed using bracket notation with zero-based indexing:

let arr = [10, 20, 30, 40]
puts(arr[0])   # 10
puts(arr[1])   # 20
puts(arr[3])   # 40

Mutability #

Arrays are mutable - methods that modify arrays change them in place:

let arr = [1, 2, 3]

# Add element (modifies arr)
arr.push(4)
puts(arr)  # [1, 2, 3, 4]

# Remove last element (returns removed element)
let last = arr.pop()
puts(last)  # 4
puts(arr)   # [1, 2, 3]

# Add to beginning
arr.unshift(0)
puts(arr)  # [0, 1, 2, 3]

# Remove from beginning (returns removed element)
let first = arr.shift()
puts(first)  # 0
puts(arr)    # [1, 2, 3]

Common Patterns #

Building Arrays #

let arr = []
arr.push(1)
arr.push(2)
arr.push(3)
puts(arr)  # [1, 2, 3]

Stack Operations (LIFO) #

let stack = []

# Push items
stack.push("first")
stack.push("second")
stack.push("third")

# Pop items
let item = stack.pop()
puts(item)   # third
puts(stack)  # [first, second]

Queue Operations (FIFO) #

let queue = []

# Enqueue (add to end)
queue.push("first")
queue.push("second")
queue.push("third")

# Dequeue (remove from front)
let item = queue.shift()
puts(item)   # first
puts(queue)  # [second, third]

Array Transformation with map/filter #

# Transform and filter in one chain
let nums = [1, 2, 3, 4, 5, 6]
let result = nums
    .filter(fun (x) x % 2 == 0 end)  # Get evens [2, 4, 6]
    .map(fun (x) x * x end)          # Square them [4, 16, 36]
puts(result)  # [4, 16, 36]
puts(nums)    # [1, 2, 3, 4, 5, 6] (unchanged - filter/map return new arrays)

In-Place Sorting #

let nums = [3, 1, 4, 1, 5, 9, 2, 6]
nums.sort()  # Sorts in place
puts(nums)   # [1, 1, 2, 3, 4, 5, 6, 9]

# Use sorted() for non-mutating version
let original = [5, 2, 8, 1]
let sorted = original.sorted()
puts(original)  # [5, 2, 8, 1] (unchanged)
puts(sorted)    # [1, 2, 5, 8]

Finding Elements #

let users = [
    {"name": "Alice", "age": 30},
    {"name": "Bob", "age": 25},
    {"name": "Carol", "age": 35}
]

# Find first user over 30
let user = users.find(fun (u) u["age"] > 30 end)
puts(user["name"])  # Carol

# Check if any user is under 20
let has_teen = users.any(fun (u) u["age"] < 20 end)
puts(has_teen)  # false

Aggregating Data #

let sales = [120, 450, 230, 890, 150]

# Sum
let total = sales.reduce(fun (sum, x) sum + x end, 0)
puts(total)  # 1840

# Max (using reduce)
let max_sale = sales.reduce(
    fun (max, x)
        if x > max
            x
        else
            max
        end
    end,
    0
)
puts(max_sale)  # 890

Storing and Calling Functions #

Arrays can store functions as elements, enabling dynamic function dispatch and higher-order function patterns:

# Array of operation functions
let operations = [
    fun (x) x + 1 end,
    fun (x) x * 2 end,
    fun (x) x * x end
]

puts(operations[0](5))   # 6 (5 + 1)
puts(operations[1](5))   # 10 (5 * 2)
puts(operations[2](5))   # 25 (5 * 5)

# Array of function factories
let make_adder = fun (n) fun (x) x + n end end
let make_multiplier = fun (n) fun (x) x * n end end

let factories = [make_adder, make_multiplier]

# Chain calls: get the factory, call it to create a function, then call that function
let add_ten = factories[0](10)
let multiply_five = factories[1](5)

puts(add_ten(3))        # 13
puts(multiply_five(3))  # 15

Array Methods #

Mutating Methods #

These methods modify the array in place and return nil (except pop(), shift(), and remove_at() which return the removed element).

push(value) #

Adds value to the end of the array.

Parameters:

  • value - Value to add (any type)

Returns: Nil

Example:

let arr = [1, 2, 3]
arr.push(4)
puts(arr)  # [1, 2, 3, 4]

pop() #

Removes and returns the last element of the array.

Returns: Last element

Raises: Error if array is empty

Example:

let arr = [1, 2, 3, 4]
let last = arr.pop()
puts(last)  # 4
puts(arr)   # [1, 2, 3]

shift() #

Removes and returns the first element of the array.

Returns: First element

Raises: Error if array is empty

Example:

let arr = [1, 2, 3, 4]
let first = arr.shift()
puts(first)  # 1
puts(arr)    # [2, 3, 4]

unshift(value) #

Adds value to the beginning of the array.

Parameters:

  • value - Value to add (any type)

Returns: Nil

Example:

let arr = [2, 3, 4]
arr.unshift(1)
puts(arr)  # [1, 2, 3, 4]

reverse() #

Reverses the array in place.

Returns: Nil

Example:

let arr = [1, 2, 3, 4]
arr.reverse()
puts(arr)  # [4, 3, 2, 1]

sort() #

Sorts the array in place in ascending order. Works with numbers and strings.

Returns: Nil

Example:

let nums = [3, 1, 4, 1, 5, 9, 2, 6]
nums.sort()
puts(nums)  # [1, 1, 2, 3, 4, 5, 6, 9]

let words = ["dog", "cat", "bird", "fish"]
words.sort()
puts(words)  # [bird, cat, dog, fish]

clear() #

Removes all elements from the array.

Returns: Nil

Example:

let arr = [1, 2, 3, 4, 5]
arr.clear()
puts(arr)  # []

insert(index, value) #

Inserts value at the specified index, shifting subsequent elements.

Parameters:

  • index - Zero-based index where to insert (Num)
  • value - Value to insert (any type)

Returns: Nil

Raises: Error if index > array length

Example:

let arr = [1, 2, 4, 5]
arr.insert(2, 3)
puts(arr)  # [1, 2, 3, 4, 5]

remove(value) #

Removes the first occurrence of value from the array.

Parameters:

  • value - Value to remove (any type)

Returns: Bool (true if element was found and removed, false otherwise)

Example:

let arr = [1, 2, 3, 2, 4]
let found = arr.remove(2)
puts(found)  # true
puts(arr)    # [1, 3, 2, 4]

remove_at(index) #

Removes and returns the element at the specified index.

Parameters:

  • index - Zero-based index (Num)

Returns: Removed element

Raises: Error if index out of bounds

Example:

let arr = [1, 2, 3, 4, 5]
let removed = arr.remove_at(2)
puts(removed)  # 3
puts(arr)      # [1, 2, 4, 5]

Non-Mutating Methods #

These methods return new arrays or values without modifying the original array.

len() #

Returns the number of elements in the array.

Returns: Int

Example:

let arr = [1, 2, 3, 4]
puts(arr.len())  # 4

get(index) #

Returns the element at the specified index.

Parameters:

  • index - Zero-based index (Int)

Returns: Element at index

Raises: Error if index out of bounds

Example:

let arr = ["a", "b", "c"]
puts(arr.get(0))  # a
puts(arr.get(1))  # b

first() #

Returns the first element of the array.

Returns: First element

Raises: Error if array is empty

Example:

let arr = [10, 20, 30]
puts(arr.first())  # 10

last() #

Returns the last element of the array.

Returns: Last element

Raises: Error if array is empty

Example:

let arr = [10, 20, 30]
puts(arr.last())  # 30

reversed() #

Returns a new array with elements in reverse order.

Returns: Array (new reversed array)

Example:

let arr = [1, 2, 3, 4]
let rev = arr.reversed()
puts(rev)  # [4, 3, 2, 1]
puts(arr)  # [1, 2, 3, 4] (original unchanged)

sorted() #

Returns a new array with elements sorted in ascending order.

Returns: Array (new sorted array)

Example:

let nums = [3, 1, 4, 1, 5, 9, 2, 6]
let sorted = nums.sorted()
puts(sorted)  # [1, 1, 2, 3, 4, 5, 6, 9]
puts(nums)    # [3, 1, 4, 1, 5, 9, 2, 6] (original unchanged)

slice(start, end) #

Returns a new array containing elements from start index up to (but not including) end index. Supports negative indices to count from the end.

Parameters:

  • start - Starting index (Int), negative counts from end
  • end - Ending index (Int, exclusive), negative counts from end

Returns: Array (new slice)

Example:

let arr = [0, 1, 2, 3, 4, 5]
puts(arr.slice(1, 4))    # [1, 2, 3]
puts(arr.slice(0, 2))    # [0, 1]
puts(arr.slice(2, -1))   # [2, 3, 4]
puts(arr.slice(-3, -1))  # [3, 4]

concat(other) #

Returns a new array combining this array with another array.

Parameters:

  • other - Array to concatenate

Returns: Array (new combined array)

Example:

let a = [1, 2, 3]
let b = [4, 5, 6]
let combined = a.concat(b)
puts(combined)  # [1, 2, 3, 4, 5, 6]
puts(a)         # [1, 2, 3] (original unchanged)

join(separator) #

Converts array to a string with elements joined by separator.

Parameters:

  • separator - String to place between elements

Returns: Str (joined string)

Example:

let arr = ["a", "b", "c"]
puts(arr.join(", "))     # a, b, c
puts(arr.join(""))       # abc
puts([1, 2, 3].join("-")) # 1-2-3

contains(value) #

Checks if the array contains the specified value.

Parameters:

  • value - Value to search for (any type)

Returns: Bool (true if found)

Example:

let arr = [1, 2, 3, 4, 5]
puts(arr.contains(3))  # true
puts(arr.contains(6))  # false

index_of(value) #

Returns the index of the first occurrence of value, or -1 if not found.

Parameters:

  • value - Value to search for (any type)

Returns: Int (index or -1)

Example:

let arr = ["a", "b", "c", "b"]
puts(arr.index_of("b"))  # 1
puts(arr.index_of("x"))  # -1

count(value) #

Counts how many times a value appears in the array.

Parameters:

  • value - Value to count (any type)

Returns: Int (count)

Example:

let arr = [1, 2, 3, 2, 4, 2]
puts(arr.count(2))  # 3
puts(arr.count(5))  # 0

empty() #

Checks if the array is empty.

Returns: Bool (true if empty)

Example:

let arr1 = []
let arr2 = [1, 2, 3]
puts(arr1.empty())  # true
puts(arr2.empty())  # false

Higher-Order Methods #

These methods take functions as arguments and return new arrays or values.

map(fn) #

Transform each element by applying a function. Returns a new array with transformed elements.

Parameters:

  • fn - Function that takes one element and returns transformed value

Returns: Array (new transformed array)

Example:

let nums = [1, 2, 3, 4]
let doubled = nums.map(fun (x) x * 2 end)
puts(doubled)  # [2, 4, 6, 8]
puts(nums)     # [1, 2, 3, 4] (original unchanged)

let words = ["hello", "world"]
let upper = words.map(fun (s) s.upper() end)
puts(upper)  # [HELLO, WORLD]

filter(fn) #

Select elements that match a predicate function. Returns a new array with matching elements.

Parameters:

  • fn - Function that takes one element and returns Bool

Returns: Array (new filtered array)

Example:

let nums = [1, 2, 3, 4, 5, 6]
let evens = nums.filter(fun (x) x % 2 == 0 end)
puts(evens)  # [2, 4, 6]
puts(nums)   # [1, 2, 3, 4, 5, 6] (original unchanged)

each(fn) #

Iterate over elements, calling function for each. Used for side effects, returns nil.

Parameters:

  • fn - Function taking element (and optionally index)

Returns: Nil

Example:

let arr = ["a", "b", "c"]
arr.each(fun (elem) puts(elem) end)
# Output:
# a
# b
# c

# With index
arr.each(fun (elem, idx)
    puts(idx .. ": " .. elem)
end)
# Output:
# 0: a
# 1: b
# 2: c

reduce(fn, initial) #

Reduce array to single value by applying accumulator function.

Parameters:

  • fn - Function taking (accumulator, element) and returning new accumulator
  • initial - Initial accumulator value

Returns: Final accumulator value (any type)

Example:

let nums = [1, 2, 3, 4, 5]
let sum = nums.reduce(fun (acc, x) acc + x end, 0)
puts(sum)  # 15

let product = nums.reduce(fun (acc, x) acc * x end, 1)
puts(product)  # 120

any(fn) #

Check if any element matches predicate.

Parameters:

  • fn - Function that takes one element and returns Bool

Returns: Bool (true if any match)

Example:

let nums = [1, 2, 3, 4, 5]
puts(nums.any(fun (x) x > 3 end))  # true
puts(nums.any(fun (x) x > 10 end)) # false

all(fn) #

Check if all elements match predicate.

Parameters:

  • fn - Function that takes one element and returns Bool

Returns: Bool (true if all match)

Example:

let nums = [2, 4, 6, 8]
puts(nums.all(fun (x) x % 2 == 0 end))  # true
puts(nums.all(fun (x) x > 5 end))       # false

find(fn) #

Find first element matching predicate. Returns nil if not found.

Parameters:

  • fn - Function that takes one element and returns Bool

Returns: First matching element or nil

Example:

let nums = [1, 2, 3, 4, 5]
let found = nums.find(fun (x) x > 3 end)
puts(found)  # 4

let not_found = nums.find(fun (x) x > 10 end)
puts(not_found)  # nil

find_index(fn) #

Find index of first element matching predicate. Returns -1 if not found.

Parameters:

  • fn - Function that takes one element and returns Bool

Returns: Int (index or -1)

Example:

let words = ["cat", "dog", "elephant", "bird"]
let idx = words.find_index(fun (w) w.len() > 5 end)
puts(idx)  # 2 (elephant is at index 2)

let not_found = words.find_index(fun (w) w.len() > 10 end)
puts(not_found)  # -1

Notes #

  • Arrays are zero-indexed (first element is at index 0)
  • Arrays are heterogeneous (can contain mixed types)
  • Arrays are mutable - most methods modify the array in place
  • Mutating methods: push(), pop(), shift(), unshift(), reverse(), sort(), clear(), insert(), remove(), remove_at()
  • Non-mutating alternatives: Use sorted() and reversed() for copies
  • Higher-order methods (map, filter, etc.) always return new arrays
  • Out-of-bounds access raises an error
  • Empty array operations (pop/shift/first/last on []) raise errors
  • Negative indices in slice() count backwards from the end