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    3

Then 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.

All arrays in BoxLang are passed by passed by reference. Please remember this when working with arrays and passing them to functions. There is also the passby=reference|value attribute to function arguments where you can decide whether to pass by reference or value.

💻 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.

📚 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

Function
Purpose
Example

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

Function
Purpose
Example

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

Function
Purpose
Example

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

Function
Purpose
Example

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

Function
Purpose
Example

arraySort()

Sort array

arraySort(arr, "text") or with callback

📏 Information Functions

Function
Purpose
Example

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

Function
Purpose
Example

arrayEach()

Iterate each element

arrayEach(arr, (item) => println(item))

⚙️ 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 vs Java Indexing: Remember that BoxLang arrays use 1-based indexing, while Java List methods use 0-based indexing. When using Java methods directly, adjust your indices accordingly:

  • arr.get(0) in Java = arr[1] in BoxLang

  • arr.add(0, item) in Java = arr.insertAt(1, item) in BoxLang

🎯 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:

Key Differences: BoxLang vs Java Methods

Operation
BoxLang Method (1-based)
Java Method (0-based)

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)

Try it online!

🔀 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

  1. Consistent Structure: Ensure all sub-arrays have the same length when representing regular grids

  2. Bounds Checking: Always verify array indices exist before accessing nested elements

  3. Memory Considerations: Large multi-dimensional arrays can consume significant memory

  4. Initialization: Pre-populate arrays with default values to avoid null reference errors

  5. 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.

🔁 Looping Over Arrays

You can use different constructs for looping over arrays:

  • for loops

  • loop constructs

  • each() 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

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

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.

The signature of the closure/lambda is the following

Here are a few simple examples:

Here is another example when listening to a specific index:

Last updated

Was this helpful?