Definition
A ColdFusion array is an ordered, zero-gap collection of values that you access by numeric position. Put simply, it’s a list where each item has a position number, and you can add, read, change, and remove items using that number. In CFML (ColdFusion Markup Language), arrays are mutable, can hold mixed data types (numbers, strings, structs, queries, other arrays), and use 1-based indexing—the first element is at position 1, not 0.
How It Works
Core characteristics
- Ordered: Elements maintain insertion order.
- 1-based index: The first element is at index 1.
- Dynamic size: Arrays grow or shrink automatically as you add or remove elements.
- Heterogeneous: A single array can hold different types at the same time.
- Mutable: Operations like append, insert, delete, and sort modify the array in place.
- Reference type: When you assign an array to another variable, both variables reference the same array unless you explicitly clone it (e.g., with Duplicate()).
Indexing and access
- Read: value = myArray[1]
- Write/replace: myArray[2] = “beta”
- Insert at position: ArrayInsertAt(myArray, 1, “alpha”)
- Delete at position: ArrayDeleteAt(myArray, 3)
- Length/size: ArrayLen(myArray)
- Check bounds: ArrayIsDefined(myArray, 2)
Remember: out-of-range access throws an error, so bounds checking is important in robust code.
Multidimensional arrays
ColdFusion supports multidimensional arrays (arrays of arrays), typically used to represent grids, matrices, or nested structures.
- Literal nested arrays (CFScript): grid = [ [1,2], [3,4] ]; access as grid[2][1] -> 3
- Using ArrayNew:
- One-dimensional: ArrayNew(1)
- Two-dimensional: ArrayNew(2) and then set elements like grid[1][1] = “A”
Multidimensional arrays grow as you assign new indices, but it’s often cleaner to build inner arrays first and then append them.
Syntax and Common Operations
Creating arrays
-
CFScript literals:
- myArray = [];
- nums = [1, 2, 3];
- mixed = [1, “two”, now(), {name=”Kim”}, [9, 8]];
-
CFML tags:
-
- <cfset ArrayAppend(myArray, “alpha”)>
-
Tip: Literals ([]) are concise and readable in CFScript. ArrayNew() is often used in tag-based templates.
Reading and writing elements
- Read by index: item = myArray[1]
- Write/replace: myArray[1] = “first”
- Append:
- CFScript: ArrayAppend(myArray, “last”)
- Tag: <cfset ArrayAppend(myArray, “last”)>
- Insert at position: ArrayInsertAt(myArray, 2, “middle”)
- Remove by position: ArrayDeleteAt(myArray, 2)
- Clear all: ArrayClear(myArray)
- Does index exist: ArrayIsDefined(myArray, 3)
Iteration patterns
- Index loop (useful for positional access):
- for (i = 1; i <= ArrayLen(myArray); i++) { doSomething(myArray[i]); }
- For-each style (read-only Iteration):
- for (item in myArray) { doSomething(item); }
When Performance matters, store ArrayLen(myArray) in a variable before the loop to avoid repeatedly computing it.
Searching, sorting, and transforming
- Find item position:
- pos = ArrayFind(myArray, “needle”)
- pos = ArrayFindNoCase(myArray, “needle”) for case-insensitive string search
- Contains check:
- hasIt = ArrayFind(myArray, value) GT 0
- Sort:
- ArraySort(nums, “numeric”, “asc”)
- ArraySort(names, “textNoCase”, “desc”)
- Map/filter/reduce:
- upperNames = ArrayMap(names, function(n) { return UCase(n); })
- shortNames = ArrayFilter(names, function(n) { return Len(n) LTE 4; })
- total = ArrayReduce(nums, function(acc, n) { return acc + n; }, 0)
These high-level functions make array processing expressive and succinct.
Practical Example: Building a JSON API Payload
Scenario: You need to return a JSON response listing active users with their IDs and emails.
CFScript:
users = [
{id=101, name=”Ana”, email=”ana@example.com”, active=true},
{id=102, name=”Bo”, email=”bo@example.com”, active=false},
{id=103, name=”Cyd”, email=”cyd@example.com”, active=true}
];
// Keep only active users
activeUsers = ArrayFilter(users, function(u) { return u.active; });
// Sort by name ascending (case-insensitive)
ArraySort(activeUsers, “textNoCase”, “asc”);
// Transform to the payload format
payload = ArrayMap(activeUsers, function(u) {
return { userId=u.id, email=u.email };
});
// Serialize to JSON for an API
jsonResponse = SerializeJSON(payload);
// Result: [{“userId”:101,”email”:”ana@example.com”},{“userId”:103,”email”:”cyd@example.com”}]
This example shows how arrays in CFML work naturally with JSON, how to filter and sort records, and how to transform data using ArrayMap. It also highlights why arrays are ideal for building ordered payloads.
Use Cases
- Managing ordered lists such as menus, tags, and Navigation items.
- Preparing data for JSON APIs or AJAX responses via SerializeJSON().
- Building stacks or queues for workflow processing.
- Aggregating results from service calls (e.g., collecting file paths, email addresses).
- Representing matrices/boards (multidimensional arrays) for analytical calculations or grid UIs.
- Batch operations, like bulk updates or ordered processing of tasks.
Best practices
- Prefer literals for readability: Use [] for creation where possible.
- Respect 1-based indexing: Avoid off-by-one errors; explicitly document index assumptions.
- Avoid sparse arrays: Don’t skip indices (e.g., setting [5] without [1..4]); it complicates iteration.
- Be consistent with types: While CF arrays are heterogeneous, keeping element types consistent simplifies code and reduces bugs.
- Clone when needed: Because arrays are reference types, use Duplicate(myArray) for a deep copy before making changes you don’t want to affect the original.
- Pre-size for Performance: When you know the final size, use ArrayResize(myArray, n) to reduce reallocations during large loops.
- Cache ArrayLen in loops: Store len = ArrayLen(a) before iterating to avoid repeated function calls.
- Use high-level functions: ArrayMap, ArrayFilter, ArrayReduce, ArraySort improve clarity and reduce boilerplate.
- Guard boundaries: Use ArrayIsDefined(a, i) or check i >= 1 and i <= ArrayLen(a) before reading/writing by index.
- Thread safety: When arrays live in shared scopes (Application, Session, Server), use cflock around read/write operations to avoid Race conditions.
Pros and cons Compared to Other CFML Collections
Pros:
- Ordered by default and easy to sort.
- Natural fit for JSON arrays and API payloads.
- Flexible and dynamic; easy to grow and shrink.
- Rich built-in functions for searching, mapping, filtering, reducing.
Cons:
- Index-based access is less descriptive than key-based access; for named fields use structs.
- 1-based indexing can surprise developers used to 0-based languages.
- Sparse arrays and mixed types can lead to subtle bugs if not disciplined.
- For key/value lookups, arrays are less efficient than structs.
When to use arrays vs structs:
- Use an array when you care about order or position.
- Use a struct (dictionary) when you care about named keys and fast lookups.
- Combine them for complex data (e.g., array of structs for a list of records).
Key Points
- ColdFusion arrays are ordered, 1-based, mutable collections that support mixed types.
- They integrate smoothly with JSON via SerializeJSON().
- Use ArrayMap/Filter/Reduce/Sort for clear and concise data transformations.
- Clone with Duplicate() to avoid unintended side effects due to reference semantics.
- Choose arrays for ordered lists and structs for keyed data; combine as needed.
FAQ
Are ColdFusion arrays zero-based or one-based?
They are one-based. The first element is at index 1. This is a common source of off-by-one errors if you’re used to 0-based languages.
How do I copy an array without affecting the original?
Use Duplicate(). Example: copy = Duplicate(originalArray). Assigning directly (copy = originalArray) creates another reference to the same array, so changes to one affect the other.
What’s the difference between an array and a struct in CFML?
An array is an ordered collection accessed by numeric index. A struct is an unordered key/value map accessed by string keys. Arrays are great for sequences and preserving order, while structs are best for labeled data and quick lookups.
How do I convert a query to an array for JSON output?
Build an array of structs, one per row. Example:
- rows = [];
- for (i = 1; i <= myQuery.recordCount; i++) {
row = {};
for (col in myQuery.columnList) {
row[col] = myQuery[col][i];
}
ArrayAppend(rows, row);
} - json = SerializeJSON(rows)
This yields a JSON array of row objects suitable for APIs.
