Boxlang 1.x Stable Released
BoxLang : A Modern Dynamic JVM Language
LogoLogo
APIDocsDownloadTrySourceSupport
  • Introduction
    • Contributing Guide
    • Release History
      • 1.2.0
      • 1.1.0
      • 1.0.1
      • 1.0.0
      • RC Stage
        • 1.0.0-RC.1
        • 1.0.0-RC.2
        • 1.0.0-RC.3
      • Beta Stage
        • 1.0.0-Beta27
        • 1.0.0-Beta26
        • 1.0.0-Beta25
        • 1.0.0-Beta24
        • 1.0.0-Beta23
        • 1.0.0-Beta22
        • 1.0.0-Beta21
        • 1.0.0-Beta20
        • 1.0.0-Beta19
        • 1.0.0-Beta18
        • 1.0.0-Beta17
        • 1.0.0-Beta16
        • 1.0.0-Beta15
        • 1.0.0-Beta14
        • 1.0.0-Beta13
        • 1.0.0-Beta12
        • 1.0.0-Beta11
        • 1.0.0-Beta10
        • 1.0.0-Beta9
        • 1.0.0-Beta8
        • 1.0.0-Beta7
        • 1.0.0-Beta6
        • 1.0.0-Beta5
        • 1.0.0-Beta 4
        • 1.0.0-Beta3
        • 1.0.0-Beta2
    • About This Book
      • Authors
  • Getting Started
    • Overview
      • Multi-Runtime
      • Instructions & Interpreters
      • CommandBox CLI
      • Quick Syntax Guide
        • Differences From CFML
      • Frequently Asked Questions
      • Running ColdFusion/CFML Apps
        • Migrating from Adobe ColdFusion
        • Migrating From Lucee CFML
    • Installation
      • BoxLang Quick Installer
      • BoxLang Version Manager (BVM)
      • Modules
    • Running BoxLang
      • AWS Lambda
      • CommandBox
      • Chromebooks
      • CLI Scripting
      • Docker
      • GitHub Actions
      • JSR-223 Scripting
      • MiniServer
      • Try BoxLang!
    • BoxLang Cloud Servers
      • Microsoft Azure
      • Amazon Web Services
    • IDE & Tooling
      • BoxLang Debugger
        • MiniServer Debugging
        • CommandBox Debugging
      • BoxLang Compiler
      • CFML Feature Audit
      • CFML to BoxLang Transpiler
    • Runtime Configuration
      • Directives
      • Caches
      • Datasources
      • Experimental
      • Executors
      • Logging
      • Maven Integration
      • Modules
      • Security
  • BoxLang Language
    • Program Structure
    • Syntax & Semantics
      • Comments
      • Variables
      • Variable Scopes
      • Operators
      • Null & Nothingness
      • Strings
      • Numbers
      • Dates & Times
      • JSON
      • Arrays
      • Structures
      • Queries
      • Datasources
      • Conditionals
      • Attempts
      • Data Navigators
      • Exception Management
      • Code Locking
      • Closures => Context Aware
      • Lambdas -> Pure Functions
      • Includes
      • Threading
    • Classes & O.O.
      • Properties
      • Functions
      • Static Constructs
      • Final Constructs
      • Abstract Constructs
      • Interfaces
    • Reference
      • API Docs
      • Lexical Elements
        • Scopes and Constants
        • Keywords
        • Operators
        • Literals
        • Comments
        • Tokens
        • Semicolons
        • Identifiers
        • Packages and Imports
        • Java Interoperability
        • Errors
      • Types
        • array
        • class
        • datetime
        • file
        • numeric
        • query
        • stream
        • string
        • struct
        • xml
      • Built-in Functions
        • array
          • ArrayAppend
          • ArrayAvg
          • ArrayClear
          • ArrayContains
          • ArrayContainsNoCase
          • ArrayDelete
          • ArrayDeleteAt
          • ArrayDeleteNoCase
          • ArrayEach
          • ArrayEvery
          • ArrayFilter
          • ArrayFind
          • ArrayFindAll
          • ArrayFindAllNoCase
          • ArrayFindNoCase
          • ArrayFirst
          • ArrayGetMetadata
          • ArrayIndexExists
          • ArrayInsertAt
          • ArrayIsDefined
          • ArrayLast
          • ArrayMap
          • ArrayMax
          • ArrayMedian
          • ArrayMerge
          • ArrayMid
          • ArrayMin
          • ArrayNew
          • ArrayPop
          • ArrayPrepend
          • ArrayPush
          • ArrayRange
          • ArrayReduce
          • ArrayReduceRight
          • ArrayResize
          • ArrayReverse
          • ArraySet
          • ArrayShift
          • ArraySlice
          • ArraySome
          • ArraySort
          • ArraySplice
          • ArraySum
          • ArraySwap
          • ArrayToList
          • ArrayToStruct
          • ArrayUnshift
        • async
          • ExecutorGet
          • ExecutorHas
          • ExecutorList
          • ExecutorNew
          • ExecutorShutdown
          • ExecutorStatus
          • FutureNew
          • IsInThread
          • isThreadAlive
          • IsThreadInterrupted
          • RunAsync
          • ThreadInterrupt
          • ThreadJoin
          • ThreadNew
          • ThreadTerminate
        • binary
          • BinaryDecode
          • BinaryEncode
          • BitAnd
          • BitMaskClear
          • BitMaskRead
          • BitMaskSet
          • BitNot
          • BitOr
          • bitShln
          • bitShrn
          • BitXor
        • cache
          • Cache
          • CacheFilter
          • CacheNames
          • CacheProviders
          • CacheService
        • cli
          • CLIClear
          • CLIExit
          • CLIGetArgs
          • CLIRead
        • conversion
          • DataNavigate
          • JSONDeserialize
          • JSONPrettify
          • JSONSerialize
          • LSParseNumber
          • ParseNumber
          • ToBase64
          • ToBinary
          • ToModifiable
          • ToNumeric
          • ToScript
          • ToString
          • ToUnmodifiable
        • decision
          • ArrayIsEmpty
          • arrayIsEmpty
          • Attempt
          • IsArray
          • IsBinary
          • IsBoolean
          • IsClosure
          • IsCustomFunction
          • IsDate
          • IsDateObject
          • IsDebugMode
          • IsDefined
          • IsEmpty
          • IsFileObject
          • IsIPv6
          • IsJSON
          • IsLeapYear
          • IsLocalHost
          • IsNull
          • IsNumeric
          • IsNumericDate
          • IsObject
          • IsQuery
          • IsSimpleValue
          • IsStruct
          • IsValid
          • IsXML
          • IsXmlAttribute
          • IsXMLDoc
          • IsXMLElem
          • IsXMLNode
          • IsXMLRoot
          • LSIsNumeric
          • structIsEmpty
        • encryption
          • Decrypt
          • DecryptBinary
          • Encrypt
          • EncryptBinary
          • GeneratePBKDFKey
          • GenerateSecretKey
          • Hash
          • Hash40
          • Hmac
        • format
          • BooleanFormat
          • DecimalFormat
          • LSNumberFormat
          • NumberFormat
        • i18n
          • ClearLocale
          • CurrencyFormat
          • GetLocale
          • GetLocaleDisplayName
          • GetLocaleInfo
          • IsCurrency
          • LSCurrencyFormat
          • LSIsCurrency
          • LSParseCurrency
          • ParseCurrency
          • SetLocale
        • io
          • ContractPath
          • CreateTempDirectory
          • CreateTempFile
          • DirectoryCopy
          • DirectoryCreate
          • DirectoryDelete
          • DirectoryExists
          • DirectoryList
          • DirectoryMove
          • DirectoryRename
          • ExpandPath
          • FileAppend
          • FileClose
          • FileCopy
          • FileDelete
          • FileExists
          • FileGetMimeType
          • FileInfo
          • FileIsEOF
          • FileMove
          • FileOpen
          • FileRead
          • FileReadBinary
          • FileReadLine
          • FileSeek
          • FileSetAccessMode
          • FileSetAttribute
          • FileSetLastModified
          • FileSkipBytes
          • FileWrite
          • FileWriteLine
          • GetCanonicalPath
          • GetDirectoryFromPath
          • GetFileInfo
          • getTempFile
        • java
          • CreateDynamicProxy
        • jdbc
          • IsInTransaction
          • IsWithinTransaction
          • PreserveSingleQuotes
          • QueryExecute
          • TransactionCommit
          • TransactionRollback
          • TransactionSetSavepoint
        • list
          • GetToken
          • ListAppend
          • ListAvg
          • ListChangeDelims
          • ListCompact
          • ListContains
          • ListContainsNoCase
          • ListDeleteAt
          • ListEach
          • ListEvery
          • ListFilter
          • ListFind
          • ListFindNoCase
          • ListFirst
          • ListGetAt
          • ListIndexExists
          • ListInsertAt
          • ListItemTrim
          • ListLast
          • ListLen
          • ListMap
          • ListPrepend
          • ListQualify
          • ListReduceRight
          • ListRemoveDuplicates
          • ListRest
          • ListSetAt
          • ListSome
          • ListSort
          • ListToArray
          • ListTrim
          • ListValueCount
          • ListValueCountNoCase
        • math
          • Abs
          • Acos
          • Asin
          • Atn
          • Ceiling
          • Cos
          • DecrementValue
          • Exp
          • Fix
          • Floor
          • FormatBaseN
          • IncrementValue
          • InputBaseN
          • Int
          • Log
          • Log10
          • Max
          • Min
          • Pi
          • PrecisionEvaluate
          • Rand
          • Randomize
          • RandRange
          • Round
          • Sgn
          • Sin
          • Sqr
          • Tan
        • query
          • QueryAddColumn
          • QueryAddRow
          • QueryAppend
          • QueryClear
          • QueryColumnArray
          • QueryColumnCount
          • QueryColumnData
          • QueryColumnExists
          • QueryColumnList
          • QueryCurrentRow
          • QueryDeleteColumn
          • QueryDeleteRow
          • QueryEach
          • QueryEvery
          • QueryFilter
          • QueryGetCell
          • QueryGetResult
          • QueryInsertAt
          • QueryKeyExists
          • QueryMap
          • QueryNew
          • QueryPrepend
          • QueryRecordCount
          • QueryReduce
          • QueryRegisterFunction
          • QueryReverse
          • QueryRowData
          • QueryRowSwap
          • QuerySetCell
          • QuerySetRow
          • QuerySlice
          • QuerySome
          • QuerySort
        • runtime
          • BoxLangBIFProxy
        • scheduler
          • SchedulerGet
          • SchedulerGetAll
          • SchedulerList
          • SchedulerRestart
          • SchedulerShutdown
          • SchedulerStart
          • SchedulerStats
        • string
          • Ascii
          • CamelCase
          • Char
          • CharsetDecode
          • CharsetEncode
          • Compare
          • CompareNoCase
          • Find
          • FindNoCase
          • FindOneOf
          • Insert
          • JSStringFormat
          • KebabCase
          • LCase
          • Left
          • ListReduce
          • LJustify
          • LTrim
          • Mid
          • ParagraphFormat
          • PascalCase
          • QueryStringToStruct
          • ReEscape
          • ReFind
          • reFindNoCase
          • ReMatch
          • reMatchNoCase
          • RemoveChars
          • RepeatString
          • Replace
          • ReplaceList
          • ReplaceListNoCase
          • ReplaceNoCase
          • ReReplace
          • reReplaceNoCase
          • Reverse
          • Right
          • RJustify
          • RTrim
          • Slugify
          • SnakeCase
          • SpanExcluding
          • SpanIncluding
          • SQLPrettify
          • StringBind
          • StringEach
          • StringEvery
          • StringFilter
          • StringMap
          • StringReduce
          • StringReduceRight
          • StringSome
          • StringSort
          • StripCR
          • Trim
          • TrueFalseFormat
          • UCase
          • UCFirst
          • Val
          • Wrap
          • YesNoFormat
        • struct
          • StructAppend
          • StructClear
          • StructCopy
          • StructDelete
          • StructEach
          • StructEquals
          • StructEvery
          • StructFilter
          • StructFind
          • StructFindKey
          • StructFindValue
          • StructGet
          • StructGetMetadata
          • StructInsert
          • StructIsCaseSensitive
          • StructIsOrdered
          • StructKeyArray
          • StructKeyExists
          • StructKeyList
          • StructKeyTranslate
          • StructMap
          • StructNew
          • StructReduce
          • StructSome
          • StructSort
          • StructToQueryString
          • StructToSorted
          • StructUpdate
          • StructValueArray
        • system
          • ApplicationRestart
          • ApplicationStartTime
          • ApplicationStop
          • BoxAnnounce
          • BoxAnnounceAsync
          • BoxModuleReload
          • BoxRegisterInterceptionPoints
          • BoxRegisterInterceptor
          • BoxRegisterRequestInterceptor
          • BoxUnregisterInterceptor
          • BoxUnregisterRequestInterceptor
          • CallStackGet
          • CreateGUID
          • CreateObject
          • CreateUUID
          • DE
          • DebugBoxContexts
          • Dump
          • Duplicate
          • echo
          • EncodeForHTML
          • GetApplicationMetadata
          • GetBaseTagData
          • GetBaseTagList
          • GetBaseTemplatePath
          • GetBoxContext
          • GetBoxRuntime
          • GetBoxVersionInfo
          • GetClassMetadata
          • GetComponentList
          • GetContextRoot
          • GetCurrentTemplatePath
          • GetFileFromPath
          • GetFunctionCalledName
          • GetFunctionList
          • GetModuleInfo
          • GetModuleList
          • GetRequestClassLoader
          • GetSemver
          • GetSystemSetting
          • GetTempDirectory
          • GetTickCount
          • htmlEditFormat
          • IIF
          • Invoke
          • IsInstanceOf
          • JavaCast
          • ObjectDeserialize
          • ObjectSerialize
          • PagePoolClear
          • Print
          • Println
          • RunThreadInContext
          • SessionInvalidate
          • SessionRotate
          • SessionStartTime
          • Sleep
          • SystemCacheClear
          • SystemExecute
          • SystemOutput
          • Throw
          • Trace
          • URLDecode
          • URLEncodedFormat
          • writeDump
          • WriteLog
          • WriteOutput
        • temporal
          • ClearTimezone
          • CreateDate
          • CreateDateTime
          • CreateODBCDate
          • CreateODBCDateTime
          • CreateODBCTime
          • CreateTime
          • CreateTimeSpan
          • DateAdd
          • DateCompare
          • DateConvert
          • DateDiff
          • DateFormat
          • DatePart
          • DateTimeFormat
          • Day
          • DayOfWeek
          • DayOfWeekAsString
          • DayOfWeekShortAsString
          • DayOfYear
          • DaysInMonth
          • DaysInYear
          • FirstDayOfMonth
          • GetNumericDate
          • GetTime
          • GetTimezone
          • GetTimezoneInfo
          • Hour
          • Millisecond
          • Minute
          • Month
          • MonthAsString
          • MonthShortAsString
          • Nanosecond
          • Now
          • Offset
          • ParseDateTime
          • Quarter
          • Second
          • SetTimezone
          • TimeFormat
          • Week
          • Year
        • type
          • ArrayLen
          • GetMetaData
          • Len
          • NullValue
          • StringLen
          • StructCount
        • xml
          • XMLChildPos
          • XMLElemNew
          • XMLFormat
          • XMLGetNodeType
          • XMLNew
          • XMLParse
          • XMLSearch
          • XMLTransform
          • XMLValidate
        • zip
          • Compress
          • Extract
          • IsZipFile
      • Components
        • async
          • Thread
        • cache
          • Cache
        • debug
          • Timer
        • io
          • Directory
          • File
        • jdbc
          • ProcParam
          • StoredProc
          • DBInfo
          • ProcResult
          • Query
          • QueryParam
          • Transaction
        • net
          • HTTPParam
          • HTTP
        • system
          • Throw
          • InvokeArgument
          • Application
          • Invoke
          • Abort
          • Include
          • Component
          • Execute
          • Flush
          • SaveContent
          • Output
          • Log
          • Sleep
          • Setting
          • Param
          • Lock
          • Associate
          • Silent
          • ProcessingDirective
          • Trace
          • Exit
          • Dump
          • Loop
        • xml
          • XML
        • zip
          • Zip
      • Exceptions
  • BoxLang Framework
    • Application.bx
    • Asynchronous Programming
    • Caching
      • Cache Service
      • BoxCache Provider
      • Custom Cache Providers
      • Custom Object Stores
      • Custom Eviction Policies
    • File Handling
    • Interceptors
      • Core Interception Points
        • Application Events
        • Cache Service Events
        • Cache Provider Events
        • Cache Object Store Events
        • Datasource Service Events
        • Dump Events
        • Dynamic Object Events
        • Function Invocations
        • HTTP Events
        • Life-cycle Events
        • Logging Events
        • Module Events
        • Module Service Events
        • Object Marshalling Events
        • Query Invocations
        • Runtime Events
        • Request Context Events
        • Scheduler Events
        • Scheduler Service Events
        • Template Invocations
        • Transaction Events
      • Request Interception Points
    • HTTP/S Calls
    • Java Interop
    • JDBC Transactions
    • Modules
      • AI
      • Compat CFML
        • Reference
          • Types
            • array
            • datetime
            • numeric
            • string
            • struct
          • Built-in Functions
            • cache
              • CacheCount
              • CacheGetAsAttempt
              • CacheRegionRemove
              • CacheRemoveAll
              • CachePut
              • CacheRegionExists
              • CacheGetSession
              • CacheGetEngineProperties
              • CacheGet
              • CacheGetDefaultCacheName
              • CacheGetProperties
              • CacheSetProperties
              • CacheGetAllIds
              • CacheIdExists
              • cacheKeyExists
              • CacheRemove
              • cacheDelete
              • CacheGetAll
              • CacheGetMetadata
              • CacheGetOrFail
              • CacheClear
              • CacheRegionNew
            • conversion
              • JSONDeserialize
            • encryption
              • Hash
              • Hash40
            • format
              • HTMLCodeFormat
              • DollarFormat
            • struct
              • DeleteClientVariable
            • system
              • Throw
              • ObjectSave
              • GetFunctionData
              • GetComponentMetadata
              • GetVariable
              • GetTagData
              • GetClientVariablesList
              • GetContextRoot
              • ObjectLoad
              • SetVariable
            • temporal
              • LSWeek
              • LSDayOfWeek
              • LSIsDate
              • DateCompare
              • GetHTTPTimestring
              • LSDateTimeFormat
              • LSDateFormat
              • LSTimeFormat
              • DayOfWeekAsString
              • DayOfWeekShortAsString
              • MonthAsString
              • MonthShortAsString
              • ToLegacyDate
              • createDate
              • LSParseDateTime
              • DateTimeFormat
              • DateFormat
              • TimeFormat
            • type
              • GetMetaData
          • Components
            • net
              • HTTP
      • CSRF
      • ESAPI
      • Evaluating Code
      • FTP
      • Image Manipulation
      • INI Files
      • JDBC
      • Jython
      • Mail
      • Markdown
      • ORM
      • OSHI - Operating System + Hardware
      • Password Encryption
      • PDF
      • Redis
      • UI Forms
      • WDDX
      • Web Support
      • Yaml
  • Extra Credit
    • MVC
    • Dependency Injection
Powered by GitBook
LogoLogo

Social Media

  • X
  • FaceBook
  • LinkedIn
  • YouTube

Bug Tracking

  • Runtimes
  • IDE
  • Modules

Support

  • Professional
  • Community
  • Slack

Copyright & Register Trademark by Ortus Solutions, Corp

On this page
  • The Story of One
  • Arrays in Code
  • Multi-Dimensional Arrays
  • Creating Multi-Dimensional Arrays
  • Accessing Elements
  • Modifying Multi-Dimensional Arrays
  • Working with Multi-Dimensional Arrays
  • Practical Examples
  • Helper Functions
  • Best Practices
  • Common Methods
  • Negative Indices
  • Array Slices
  • Looping Over Arrays
  • Multi-Threaded Looping
  • Spread Operator
  • Rest Operator
  • Trailing Commas
  • Change Listeners

Was this helpful?

Edit on GitHub
Export as PDF
  1. BoxLang Language
  2. Syntax & Semantics

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.

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:

 -------------  ---------  ----------
| "Breakfast" || "Lunch" || "Dinner" |
 -------------  ---------  ----------
       1            2           3

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.

 -------------  ---------  ----------  -----------
| "Breakfast" || "Lunch" || "Dinner" || "Dessert" |
 -------------  ---------  ----------  -----------
       1            2           3           4

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:

fruits = [ "banana", "papaya", "kiwi", "apple", "orange", "grape" ]

// Basic array operations
println( "Length: " & fruits.len() )
println( "First fruit: " & fruits.first() )
println( "Last fruit: " & fruits.last() )

// Functional programming with arrays
println( "--- Functional Operations ---" )

// Map - transform each element with a lambda, no access to outside scopes
uppercaseFruits = fruits.map( fruit -> fruit.ucase() )
println( "Uppercase: " & uppercaseFruits.toString() )

// Filter - get elements matching a condition
longFruits = fruits.filter( (fruit) -> fruit.len() > 5 )
println( "Long names: " & longFruits.toString() )

// Reduce - combine all elements into a single value
totalLength = fruits.reduce( (sum, fruit) -> sum + fruit.len(), 0 )
println( "Total characters: " & totalLength )

// Find - get first matching element
foundFruit = fruits.find( (fruit) -> fruit.startsWith("a") )
println( "First fruit starting with 'a': " & foundFruit )

// Sort order elements
sortedFruits = fruits.sort( (a, b) -> a.compareNoCase(b) )
println( "Sorted: " & sortedFruits.toString() )

// Chain operations together
result = fruits
    .filter( fruit -> fruit.len() <= 6 )
    .map( fruit -> fruit.ucase() )
    .sort()
println( "Chained operations: " & result.toString() )

// forEach - perform action on each element
println( "--- Individual Fruits ---" )
fruits.each( (fruit, index) => {
    println( "#index#: #fruit#" )
} )

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

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)

// Create a simple 2D array (3x3 grid)
grid = [
    [ 1, 2, 3 ],
    [ 4, 5, 6 ],
    [ 7, 8, 9 ]
]

// Mixed data types in a 2D array
studentGrades = [
    [ "Alice", 85, 92, 78 ],
    [ "Bob", 91, 88, 95 ],
    [ "Carol", 76, 84, 89 ]
]

3D Arrays (Cube/Volume)

// 3D array representing a 2x2x2 cube
cube = [
    [
        [ 1, 2 ],
        [ 3, 4 ]
    ],
    [
        [ 5, 6 ],
        [ 7, 8 ]
    ]
]

Dynamic Creation

// Create a 5x5 matrix dynamically
matrix = []
for( row = 1; row <= 5; row++ ) {
    matrix.append( [] )
    for( col = 1; col <= 5; col++ ) {
        matrix[ row ].append( row * col )
    }
}

Accessing Elements

2D Array Access

grid = [
    [ "A1", "A2", "A3" ],
    [ "B1", "B2", "B3" ],
    [ "C1", "C2", "C3" ]
]

// Access element at row 2, column 3
println( grid[2][3] )  // Output: "B3"

// Access entire row
println( grid[1] )     // Output: ["A1", "A2", "A3"]

3D Array Access

// Access element in 3D array
println( cube[1][2][1] )  // Access layer 1, row 2, column 1

Modifying Multi-Dimensional Arrays

Adding Rows and Columns

data = [
    [ 1, 2 ],
    [ 3, 4 ]
]

// Add a new row
data.append( [ 5, 6 ] )

// Add a column to each existing row
data.each( (row) => row.append( 0 ) )

println( data )
// Output: [[1, 2, 0], [3, 4, 0], [5, 6, 0]]

Updating Elements

// Update a specific cell
data[1][2] = 99

// Update an entire row
data[2] = [ 10, 20, 30 ]

Working with Multi-Dimensional Arrays

Iterating Through 2D Arrays

matrix = [
    [ 1, 2, 3 ],
    [ 4, 5, 6 ],
    [ 7, 8, 9 ]
]

// Iterate through all elements
matrix.each( (row, rowIndex) => {
    row.each( (cell, colIndex) => {
        println( "Row #rowIndex#, Col #colIndex#: #cell#" )
    })
})

// Find specific values
matrix.each( (row) => {
    foundIndex = row.find( (cell) => cell > 5 )
    if( foundIndex > 0 ) {
        println( "Found value > 5 at column #foundIndex#" )
    }
})

Functional Programming with 2D Arrays

// Transform all elements in a 2D array
doubled = matrix.map( (row) => 
    row.map( (cell) => cell * 2 )
)

// Filter rows based on criteria
evenRows = matrix.filter( (row) => 
    row.every( (cell) => cell % 2 == 0 )
)

// Sum all elements in the matrix
total = matrix
    .map( (row) => row.reduce( (sum, cell) => sum + cell, 0 ) )
    .reduce( (sum, rowTotal) => sum + rowTotal, 0 )

Practical Examples

Game Board (Tic-Tac-Toe)

board = [
    [ " ", " ", " " ],
    [ " ", " ", " " ],
    [ " ", " ", " " ]
]

// Make moves
board[1][1] = "X"
board[2][2] = "O"
board[1][3] = "X"

// Display board
board.each( (row, index) => {
    println( "#row[1]# | #row[2]# | #row[3]#" )
    if( index < 3 ) println( "---------" )
})

Spreadsheet Data

spreadsheet = [
    [ "Name", "Age", "Department", "Salary" ],
    [ "John", 30, "Engineering", 75000 ],
    [ "Jane", 25, "Marketing", 65000 ],
    [ "Bob", 35, "Sales", 70000 ]
]

// Get all employees in Engineering
engineers = spreadsheet
    .slice( 2 )  // Skip header row
    .filter( (row) => row[3] == "Engineering" )

// Calculate average salary
salaries = spreadsheet
    .slice( 2 )
    .map( (row) => row[4] )
    
avgSalary = salaries.reduce( (sum, salary) => sum + salary, 0 ) / salaries.len()

Image Pixel Data (RGB)

// Represent a 3x3 image with RGB values
image = [
    [ [255, 0, 0], [0, 255, 0], [0, 0, 255] ],    // Red, Green, Blue
    [ [255, 255, 0], [255, 0, 255], [0, 255, 255] ], // Yellow, Magenta, Cyan
    [ [128, 128, 128], [0, 0, 0], [255, 255, 255] ]  // Gray, Black, White
]

// Access red component of pixel at (2,1)
redValue = image[2][1][1]  // Gets the red component

// Convert to grayscale
grayscale = image.map( (row) =>
    row.map( (pixel) => {
        gray = (pixel[1] + pixel[2] + pixel[3]) / 3
        return [ gray, gray, gray ]
    })
)

Helper Functions

Utility Functions for Multi-Dimensional Arrays

// Get dimensions of a 2D array
function getDimensions( array2D ) {
    return {
        "rows": array2D.len(),
        "cols": array2D.len() > 0 ? array2D[1].len() : 0
    }
}

// Transpose a 2D array (swap rows and columns)
function transpose( array2D ) {
    if( array2D.len() == 0 ) return []
    
    result = []
    for( col = 1; col <= array2D[1].len(); col++ ) {
        newRow = []
        for( row = 1; row <= array2D.len(); row++ ) {
            newRow.append( array2D[row][col] )
        }
        result.append( newRow )
    }
    return result
}

// Flatten a 2D array into 1D
function flatten( array2D ) {
    return array2D.reduce( (flat, row) => {
        flat.addAll( row )
        return flat
    }, [] )
}

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 Methods

The best way to learn about using arrays is to check out the available member functions and array functions.

// Sort an array
meals.sort( "textnocase" );

// Clear the array
meals.clear();

// Go on a diet
meals.delete( "Dessert" );
meals.deleteAt( 4 );

// Iterate
meals.each( function( element, index) {
   systemOutput( element & " " & index );
} );

// Filter an array
meals.filter( function( item ){
 return item.findNoCase( "unch" ) gt 0 ? true : false;
} );

// Convert to a list
meals.toList();

// Map/ Reduce
complexData = [ {a: 4}, {a: 18}, {a: 51} ];
newArray = arrayMap( complexData, function(item){
   return item.a;
});
writeDump(newArray);

complexData = [ {a: 4}, {a: 18}, {a: 51} ];
 sum = arrayReduce( complexData, function(prev, element)
 {
 return prev + element.a;
 }, 0 );
writeDump(sum);

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:

numbers = [1,2,3,4,5]

writedump( numbers[ -1 ] ) // 5
writedump( numbers[ -2 ] ) // 4
writedump( numbers[ -3 ] ) // 3
writedump( numbers[ -4 ] ) // 2
writedump( numbers[ -5 ] ) // 1
writedump( numbers[ -6 ] ) // EXCEPTION!!! Array index out of range

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.

// Signature
arraySlice( array, offset, length )
// Member method
array.slice( offset, length )

Tip: You can also use negative offsets.

array = [ 1, 2, 3, 4, 5, 6, 7, 8 ]
newArray = array.slice( 2, 3 )
println( newArray ) // [ 2, 3, 4 ]

Looping Over Arrays

You can use different constructs for looping over arrays:

  • for loops

  • loop constructs

  • each() closures

for( var thisMeal in meals ){
 systemOutput( "I just had #thisMeal#" );
}

for( var x = 1; x lte meals.len(); x++ ){
 systemOutput( "I just had #meals[ x ]#" );
}

meals.each( function( element, index ){
  systemOutput( "I just had #element#" );
} );

bx:loop( from=1, to=meals.len(), index=x ){
  systemOutput( "I just had #meals[ x ]#" );
}

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.

arrayEach( array, callback, parallel:boolean, maxThreads:numeric );
each( collection, callback, parallel:boolean, maxThreads:numeric );

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.

myArray.each( item => {
   myservice.process( item );
}, true, 20 );

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

numbers = [ 1, 2, 3 ]
function sum( x, y, z ){
    return x + y + z;
}
// Call the function using the spread operator
results = sum( ...numbers ) // 6

// Ignore the others
numbers = [ 1, 2, 3, 4, 5 ]
results = sum( ...numbers ) // 6

Array Definitions

numbers = [ 1, 2, 3 ]
myArray = [ 3, 4, ...numbers ]
myArray2 = [ ...numbers ]
myArray2 = [ ...numbers, 4, 66 ]

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.

function findBy( ...args ){
    writeDump( args )
}
findBy( 1, 2, 3, 4, 5 )

function findBy( entityName, ...args ){
    writeDump( args )
}
findBy( "Luis", 1, 2, 3, 4, 5 )

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!

myArray = [
    "BoxLang",
    "ColdBox",
    "TestBox",
    "CommandBox",
]
println( myArray )

myStruct = {
    name: "BoxLang",
    type: "JVM Dynamic Language",
    version: "1.0.0",
}
println( myStruct )

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.

// Listen to all changes in the array
array.$bx.registerChangeListener( closure/lambda )

// Listen to a specific index in the array
array.$bx.registerChangeListener( index, closure/lambda )

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

( Key key, any newValue, any oldValue, array ) => {}

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:

fruits = [ "banana", "papaya", "kiwi", "apple" ]
// Listen to all changes of the array: add, remove, replace, etc.
fruits.registerChangeListener( (key, newValue, oldValue, array )=>{
    println( "New value: " & newValue );
    println( "Old value: " & oldValue );
    return newValue;
} )

fruits.append( "pineapple" )
fruits.deleteAt( 1 )

println( fruits )

Here is another example when listening to a specific index:

fruits = [ "banana", "papaya", "kiwi", "apple" ]
fruits.registerChangeListener( 1, (key, newValue, oldValue, array )=>{
    println( "New value: " & newValue );
    println( "Old value: " & oldValue );
    return newValue;
} )

fruits.append( "luis" )
fruits.deleteAt( 1 )
fruits.insertAt( 1, "hello" )
PreviousJSONNextStructures

Last updated 20 days ago

Was this helpful?

Try BoxLang
Logo
Try BoxLang
Logo
Try BoxLang
Logo
Try BoxLang
Logo
Try BoxLang
Logo
Try BoxLang
Logo