Arrays
An array is a data structure consisting of a collection of elements.
Almost every programming language allows you to represent different types of collections. In BoxLang, we have three types of collections: arrays, structures, and queries.
📋 Table of Contents
An array is a number-indexed list. Imagine you had a blank piece of paper and drew a set of three small boxes in a line:
--- --- ---
| || || |
--- --- ---You could number each one by its position from left to right:
--- --- ---
| || || |
--- --- ---
1 2 3Then put strings in each box:
We have a three-element Array. BoxLang arrays can grow and shrink dynamically at runtime, just like Array Lists or Vectors in Java, so if we added an element, it’d usually go on the end or be appended at the end.
If you asked the array for the element in position two, you’d get back Lunch. Ask for the last element, and you’ll get back: Dessert.
The Story of One
Now, have you detected something funny with the ordering of the elements? Come on, look closer....... They start with 1 and not 0, now isn't that funny. BoxLang is one of the few languages where array indexes start at 1 and not 0. So if you have a PHP, Ruby, or Java background, remember that 1 is where you start. Is this good or bad? Well, we will refrain from pointing fingers for now.
💻 Arrays in Code
Let's do some code samples:
Please note that all member functions can also be used as traditional array functions. However, member functions look much better for readability.
Tip: You can use the toString() call on any array to get a string representation of its values: grid.toString()
📚 Array Built-In Functions (BIFs)
BoxLang provides a comprehensive set of array BIFs organized by functionality. All array BIFs can be called as member methods on Array objects.
🔨 Creation & Conversion Functions
arrayNew()
Create new array
arrayNew() → []
listToArray()
Convert list to array
listToArray("a,b,c") → ["a", "b", "c"]
arrayToList()
Convert array to list
arrayToList([1,2,3]) → "1,2,3"
arraySlice()
Extract portion of array
arraySlice(arr, 2, 3) → [2, 3, 4]
arrayRange()
Create range of values
arrayRange(1, 5) → [1, 2, 3, 4, 5]
arrayToStruct()
Convert to struct
arrayToStruct(arr)
➕ Modification Functions
arrayAppend()
Add element to end
arrayAppend(arr, "new")
arrayPrepend()
Add element to start
arrayPrepend(arr, "first")
arrayPush()
Add element to end
arrayPush(arr, "new")
arrayUnshift()
Add multiple to start
arrayUnshift(arr, "a", "b")
arrayPop()
Remove & return last
arrayPop(arr) → last element
arrayShift()
Remove & return first
arrayShift(arr) → first element
arrayInsertAt()
Insert at position
arrayInsertAt(arr, 2, "item")
arrayDeleteAt()
Remove at position
arrayDeleteAt(arr, 3)
arrayDelete()
Remove by value
arrayDelete(arr, "value")
arrayClear()
Remove all elements
arrayClear(arr)
arrayResize()
Change array size
arrayResize(arr, 10)
arraySet()
Set range to value
arraySet(arr, 1, 5, 0)
arraySwap()
Swap two elements
arraySwap(arr, 1, 3)
arraySplice()
Remove/replace elements
arraySplice(arr, 2, 1, "new")
🔍 Search & Filter Functions
arrayFind()
Find element index
arrayFind(arr, "value") → 3
arrayFindNoCase()
Case-insensitive find
arrayFindNoCase(arr, "VALUE") → 3
arrayFindAll()
Find all matching indices
arrayFindAll(arr, "test") → [2, 5]
arrayContains()
Check if contains
arrayContains(arr, "item") → true
arrayContainsNoCase()
Case-insensitive check
arrayContainsNoCase(arr, "ITEM") → true
arrayIndexExists()
Check if index exists
arrayIndexExists(arr, 5) → true
arrayFilter()
Filter by condition
arrayFilter(arr, (x) -> x > 5)
arrayEvery()
Test all elements
arrayEvery(arr, (x) -> x > 0) → true
arraySome()
Test any element
arraySome(arr, (x) -> x > 10) → true
arrayNone()
Test no elements match
arrayNone(arr, (x) -> x < 0) → true
🔄 Transformation Functions
arrayMap()
Transform elements
arrayMap(arr, (x) -> x * 2)
arrayReduce()
Reduce left to right
arrayReduce(arr, (sum, x) -> sum + x, 0)
arrayReduceRight()
Reduce right to left
arrayReduceRight(arr, (sum, x) -> sum + x, 0)
arrayReverse()
Reverse order
arrayReverse(arr)
arrayMerge()
Merge arrays
arrayMerge(arr1, arr2, arr3)
📊 Sorting Functions
arraySort()
Sort array
arraySort(arr, "text") or with callback
📏 Information Functions
arrayLen()
Get length
arrayLen(arr) → 5
arrayIsEmpty()
Check if empty
arrayIsEmpty(arr) → false
arrayFirst()
Get first element
arrayFirst(arr) → first element
arrayLast()
Get last element
arrayLast(arr) → last element
arrayMin()
Find minimum
arrayMin(arr) → 1
arrayMax()
Find maximum
arrayMax(arr) → 100
arraySum()
Sum all elements
arraySum(arr) → 150
arrayAvg()
Calculate average
arrayAvg(arr) → 30.0
arrayMedian()
Find median
arrayMedian(arr) → 20
arrayGetMetadata()
Get array metadata
arrayGetMetadata(arr)
🔗 Iteration Functions
arrayEach()
Iterate each element
arrayEach(arr, (item) => println(item))
Complete Reference: For detailed documentation of each function, visit the Array BIF Reference.
⚙️ Member Functions
All array BIFs can be called as member functions on Array objects for cleaner, more fluent code:
🔧 Java List Methods
Since BoxLang arrays are Java List objects (specifically ArrayList), you have access to all Java List methods:
🎯 BoxLang Array Native Methods
The BoxLang Array type provides additional methods beyond standard Java List operations. These methods are specifically designed for BoxLang's 1-based indexing and functional programming patterns:
Best Practice: Use BoxLang's 1-based methods (getAt(), setAt(), deleteAt(), insertAt()) for consistency with BoxLang conventions. Use Java's 0-based methods (get(), set(), remove(), add()) only when interfacing directly with Java code.
Key Differences: BoxLang vs Java Methods
Get element
arr.getAt(1)
arr.get(0)
Set element
arr.setAt(1, val)
arr.set(0, val)
Insert element
arr.insertAt(1, val)
arr.add(0, val)
Remove element
arr.deleteAt(1)
arr.remove(0)
Find element
arr.findIndex(val) → 1
arr.indexOf(val) → 0
Append element
arr.push(val) or arr.append(val)
arr.add(val)
🔀 Multi-Dimensional Arrays
While BoxLang arrays are inherently one-dimensional, you can create multi-dimensional structures by nesting arrays within arrays. This approach provides flexibility for representing matrices, tables, grids, and other complex data structures.
Creating Multi-Dimensional Arrays
2D Arrays (Matrix/Grid)
3D Arrays (Cube/Volume)
Dynamic Creation
Accessing Elements
2D Array Access
3D Array Access
Modifying Multi-Dimensional Arrays
Adding Rows and Columns
Updating Elements
Working with Multi-Dimensional Arrays
Iterating Through 2D Arrays
Functional Programming with 2D Arrays
Practical Examples
Game Board (Tic-Tac-Toe)
Spreadsheet Data
Image Pixel Data (RGB)
Helper Functions
Utility Functions for Multi-Dimensional Arrays
Best Practices
Consistent Structure: Ensure all sub-arrays have the same length when representing regular grids
Bounds Checking: Always verify array indices exist before accessing nested elements
Memory Considerations: Large multi-dimensional arrays can consume significant memory
Initialization: Pre-populate arrays with default values to avoid null reference errors
Documentation: Clearly document the expected structure and dimensions of your nested arrays
Multi-dimensional arrays in BoxLang provide powerful data organization capabilities while maintaining the simplicity of single-dimensional array operations.
🛠️ Common Operations
Here are some practical examples combining BIFs, member functions, and Java methods:
🔙 Negative Indices
BoxLang also supports the concept of negative indices. This allows you to retrieve the elements from the end of the array backward. So you can easily count back instead of counting forwards:
✂️ Array Slices
BoxLang supports the slicing of an array via the arraySlice() method or the slice() member function, respectively. Slicing allows you to return a new array from the start position up to the count of elements you want.
Tip: You can also use negative offsets.
🔁 Looping Over Arrays
You can use different constructs for looping over arrays:
forloopsloopconstructseach()closures
⚡ Multi-Threaded Looping
BoxLang allows you to leverage the each() operations in a multi-threaded fashion. The arrayEach() or each() functions allow for a parallel and maxThreads arguments so the iteration can happen concurrently on as many maxThreads as supported by your JVM.
This is incredibly awesome, as your callback will now be called concurrently! However, please note that once you enter concurrency land, you should shiver and tremble. Thread concurrency will be of the utmost importance, and you must ensure that scoping is done correctly and that appropriate locking strategies are in place when accessing shared scopes and/or resources. Here is where unmodifiable arrays, structs, and queries can help.
🌟 Spread Operator
Coming soon, still in development
Arrays also allow the usage of the spread operator syntax to quickly copy all or part of an existing array or object into another array or object. This operator is used by leveraging three dots ... in specific expressions.
The Spread syntax allows an iterable such as an array expression or string, to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected. Here are some examples to help you understand this operator:
Function Calls
Array Definitions
💤 Rest Operator
Coming soon, still in development
The rest operator is similar to the spread operator but behaves oppositely. Instead of expanding the literals, it contracts them into an array you designate via the ...{name} syntax. You can use this to define endless arguments for a function, for example. In this case, I can create a dynamic findBy function that takes in multiple criteria name-value pairs.
✨ Trailing Commas
BoxLang supports trailing commas when defining array and struct literals. Just in case you miss a dangling comma, we won't shout at you!
👂 Change Listeners
All arrays and structures offer the ability to listen to changes to themselves. This is all done via our $bx metadata object available on all arrays/structures. You will call the registerChangeListener() function to register a closure/lambda that will listen to changes on the array. You can listen:
To all changes in the array
To a specific index in the array
However, you must EXPLICITLY return the value that will be stored in the change.
Please note that this change listener will fire on every array access, so ensure it's performant.
The signature of the closure/lambda is the following
Please note that the Key is a BoxLang Key object, which simulates a case-insensitive string. You can use methods on it like:\
getName()getNameNoCase()toString()
Here are a few simple examples:
Here is another example when listening to a specific index:
Last updated
Was this helpful?
