Using Rexx Lists as Fast Associative Arrays: Syntax, Trade‑offs, and a Simple Benchmark
Learn how Rexx’s built‑in list type gives O(1) key lookup, simplifies iteration, and where to watch for memory or compatibility issues.
06 Jul 2025, 14:09 UTC

Problem: Slow look‑ups with manual index arrays
When you need to store configuration values or cache results by name in Rexx, the traditional approach is to keep two parallel indexed arrays—one for keys, one for values—and search linearly each time you want a value. This works for tiny tables but becomes a bottleneck as the data set grows.
Thesis: Rexx lists give O(1) key access with minimal boilerplate
The list type (sometimes called an associative array) stores elements as key‑value pairs in a hash table. Accessing list['key'] is constant‑time, insertion does not require pre‑allocation, and the built‑in FOR each key IN list DO loop lets you iterate without managing an index.
Syntax and basic usage
Create a list with the LIST keyword:
/* Create an empty list */
config = LIST
Assign a value:
config['host'] = 'example.com'
Retrieve it:
say config['host'] /* prints example.com */
If the key does not exist, Rexx returns an empty string (you can test with IF config['missing'] = '' THEN ...).
Iteration and built‑in features
To walk through all entries:
FOR key IN config DO
say key '=' config[key]
END
The loop variable key receives each distinct key exactly once, regardless of insertion order.
Worked example: benchmarking list vs. indexed array
The following script creates 10 000 random key/value pairs, measures the time to fetch a random key using the list, then repeats the same logic with two parallel indexed arrays and a linear search. Run it in any interpreter that supports lists (OpenRexx 3.6+, Regina 4.0+, or IBM z/OS Rexx with the LIST extension).
/* benchmark_list_vs_array.rexx */
numeric digits 12
call time 'R' /* reset timer */
/* ----- List version ----- */
myList = LIST
do i = 1 to 10000
key = 'k' || random(1,20000)
myList[key] = random(1,1000)
end
pick = 'k' || random(1,20000)
call time 'E'
listTime = time('E')
listValue = myList[pick] /* may be empty if key not present */
/* ----- Indexed array version ----- */
call time 'R'
keys. = '' /* stem for keys */
vals. = '' /* stem for values */
do i = 1 to 10000
k = 'k' || random(1,20000)
v = random(1,1000)
keys[i] = k
vals[i] = v
end
/* linear search */
found = 0
do j = 1 to 10000
if keys[j] = pick then do
found = j
leave
end
end
if found > 0 then arrayValue = vals[found]
else arrayValue = ''
call time 'E'
arrayTime = time('E')
/* ----- Results ----- */
say 'List lookup time :' listTime 'seconds'
say 'Array lookup time :' arrayTime 'seconds'
say 'List value :' listValue
saysay 'Array value :' arrayValue
To verify that your interpreter actually provides the list type, run a simple introspection command before the benchmark:
/* test list support */
if LIST = '' then do
say 'LIST keyword not recognized – your Rexx may lack list support.'
exit 1
end
else say 'LIST keyword recognized – proceeding.'
Replace the placeholders random calls with your own data source if you prefer deterministic keys.
Trade‑offs and limitations
- Portability: The list feature is not part of the classic IBM Rexx definition. Older interpreters (e.g., traditional IBM z/OS Rexx without the LIST extension, some embedded dialects) will raise a syntax error when they encounter
LISTorlist['key']. Always check the documentation or run the introspection snippet above. - Memory overhead: Each entry carries a hash table bucket and a key string. For very large collections (hundreds of thousands of items) the footprint can noticeably exceed that of two plain arrays. In memory‑constrained environments, profile with
MEMORYor OS tools before committing to lists. - Insertion cost: While average insertion is O(1), the underlying hash table may resize when the load factor grows. Resizing copies all existing entries, causing occasional latency spikes. If you insert tens of thousands of items in a tight loop, consider pre‑allocating a larger initial size if your interpreter offers a constructor hint (some allow
LIST SIZE=n), or batch the inserts and measure.
Actionable closing
If you are writing new Rexx scripts that need name‑based look‑ups, start with a list: it removes the manual index management, gives constant‑time access, and keeps the code readable. Verify list support early, benchmark against your actual data size, and watch memory usage when the collection grows beyond a few‑tens‑of‑thousands of entries. With those checks in place, you can reap the speed benefits of associative arrays without surprising portability or performance issues.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.