Array
In Goblin, an array is an ordered collection of values accessed by position. Values can be any Goblin type and do not need to be the same type.
Creating an Array
numbers | [2, 7, 11, 15]
numbers | [2, 7, 11, 15]
Multi-line:
names | [ "Daniel" "Dave" "Lisa" ]
names | [ "Daniel" "Dave" "Lisa" ]
Empty array:
results | []
results | []
Generate an array with collect:
zeros | collect 5 of 0 /// -> [0, 0, 0, 0, 0]
zeros | collect 5 of 0 /// -> [0, 0, 0, 0, 0]
Positional Lookup
Array lookup uses brackets:
numbers[0] /// -> 2 numbers[1] /// -> 7
numbers[0] /// -> 2 numbers[1] /// -> 7
This is intentional. Arrays use brackets for positional lookup. Maps use braces for keyed lookup. The syntax tells you what kind of operation you are reading.
numbers[0] /// positional — this is an array person{"name"} /// keyed — this is a map
numbers[0] /// positional — this is an array person{"name"} /// keyed — this is a map
If you use braces on an array, Goblin errors:
numbers{"name"} /// error: used {} on an array — arrays use positional lookup with []
numbers{"name"} /// error: used {} on an array — arrays use positional lookup with []
Reading Values
:grab_at returns a value by index without modifying the array:
val | :grab_at(numbers, 0) /// -> 2
val | :grab_at(numbers, 0) /// -> 2
:grab_first and :grab_last read the first and last elements:
first | :grab_first(numbers) last | :grab_last(numbers)
first | :grab_first(numbers) last | :grab_last(numbers)
For filtered reads, see grab_where and grab_matching.
Adding Elements
:put_last! appends to the end:
:put_last!(numbers, 99)
:put_last!(numbers, 99)
:put_first! prepends to the front:
:put_first!(numbers, 0)
:put_first!(numbers, 0)
:put_at! inserts at a specific index:
:put_at!(numbers, 2, 42)
:put_at!(numbers, 2, 42)
Updating Elements
:update_at! replaces the value at an index:
:update_at!(numbers, 0, 100)
:update_at!(numbers, 0, 100)
:update_first! and :update_last! target the ends:
:update_first!(numbers, 100) :update_last!(numbers, 100)
:update_first!(numbers, 100) :update_last!(numbers, 100)
Removing Elements
:delete_at! removes the element at an index:
:delete_at!(numbers, 0)
:delete_at!(numbers, 0)
:delete_first! and :delete_last! remove from the ends:
:delete_first!(numbers) :delete_last!(numbers)
:delete_first!(numbers) :delete_last!(numbers)
:delete_where! removes all elements matching a predicate:
:delete_where!(numbers, "is_nil")
:delete_where!(numbers, "is_nil")
Remove and Return
:reap_at! removes an element by index and returns its value:
val | :reap_at!(numbers, 0)
val | :reap_at!(numbers, 0)
:reap_first! and :reap_last! do the same from the ends:
first | :reap_first!(numbers) last | :reap_last!(numbers)
first | :reap_first!(numbers) last | :reap_last!(numbers)
Iterating
Use for to walk every element with a named variable:
for number in numbers say number xx
for number in numbers say number xx
repeat also works. Use as to name the element, or use the implicit it:
repeat numbers as number say number xx repeat numbers say it xx
repeat numbers as number say number xx repeat numbers say it xx
Checking and Counting
:count(numbers) /// -> number of elements :has(numbers, 7) /// -> true if value exists in array
:count(numbers) /// -> number of elements :has(numbers, 7) /// -> true if value exists in array
Sorting and Ordering
:sort and :reverse return new arrays without mutating:
sorted | :sort(numbers) rev | :reverse(numbers)
sorted | :sort(numbers) rev | :reverse(numbers)
For random ordering see shuffle.
Math
:sum(numbers) /// -> total :avg(numbers) /// -> average :min(numbers) /// -> smallest value :max(numbers) /// -> largest value
:sum(numbers) /// -> total :avg(numbers) /// -> average :min(numbers) /// -> smallest value :max(numbers) /// -> largest value
Deduplication
:unique returns a new array with duplicates removed. :dups returns only the duplicate values.
For statistical operations like :freq, :mode, and :sample_weighted see Collection Statistics.
Joining and Splitting
:join collapses an array into a string with a delimiter:
words | ["cave", "gold", "loot"] line | :join(words, " ") /// -> "cave gold loot"
words | ["cave", "gold", "loot"] line | :join(words, " ") /// -> "cave gold loot"
:split on a string returns an array:
parts | :split("cave gold loot", " ") /// -> ["cave", "gold", "loot"]
parts | :split("cave gold loot", " ") /// -> ["cave", "gold", "loot"]
Concatenation
Two arrays can be combined with +:
all | rest_words + common_words
all | rest_words + common_words
Goblin also uses + and ++ for string concatenation. + joins with no space, ++ joins with a space:
"Dave" + "Mustaine" /// -> "DaveMustaine" "Dave" ++ "Mustaine" /// -> "Dave Mustaine"
"Dave" + "Mustaine" /// -> "DaveMustaine" "Dave" ++ "Mustaine" /// -> "Dave Mustaine"
:pack collapses an array into a single concatenated string:
numbers | [1, 2, 3, 4, 5, 6] packed | :pack(numbers) /// -> "123456"
numbers | [1, 2, 3, 4, 5, 6] packed | :pack(numbers) /// -> "123456"
:unpack splits a string back into an array of individual characters:
:unpack(packed) /// -> [1, 2, 3, 4, 5, 6]
:unpack(packed) /// -> [1, 2, 3, 4, 5, 6]
Note: :unpack splits by character, not by original element. Round-trip only works reliably when every element is a single character or digit. For multi-character strings, use join and split instead.
Planned
:adjust will apply an action to every element and return a new array:
upper_names | :adjust(names, upper)
upper_names | :adjust(names, upper)
The full family — :adjust_first, :adjust_last, :adjust_at, :adjust_where — will follow the same pattern as the rest of the collection utilities.
Type Check
:valtype(numbers) /// -> "array"
:valtype(numbers) /// -> "array"