Stop Hand-Rolling Parallel Arrays: LotusScript's List Is the Built-In HashMap for Counting, Dedup, and Lookups
You need to count documents by category. Or dedup a list of names. Or build a lookup from a code to its label so you can resolve one without hitting a view each time. The Domino reflex is a pair of parallel arrays and a linear scan — For i = 0 To UBound(keys), compare, maybe Redim Preserve — or a temporary categorized view you read back. Both work, and both are reinventing something LotusScript has shipped since the beginning and that almost nobody uses: the List.
A List is LotusScript’s native associative array — a keyed collection, a dictionary, a hashmap, whatever you call it in the language you came from. This is a short field report on the data type hiding in plain sight: how you use it, the two operations that make it worth reaching for, and the two gotchas that bite once you do.
TL;DR
- Declare with
List:Dim total List As Long. Assign by string key:total("Sales") = 10— assigning a new key creates it. - Guard reads with
IsElement: a List has no default value, so reading a tag you never assigned raises an error, not an empty value.If IsElement(total("Sales")) Then …. - Iterate with
ForAll; inside the loop,ListTag(v)gives the current element’s key whilevis its value. - Remove one element with
Erase total("Sales"), or clear the whole List withErase total. - Gotcha: whether tags are case-sensitive follows the module’s
Option Compare, so"AB"and"ab"may or may not be the same key — normalise your keys and don’t rely on it.
The whole data type in one example
Counting by category is the canonical case, and it shows every operation at once:
Dim total List As Long
Forall doc In col.Documents Dim cat As String cat = doc.Category(0) If IsElement(total(cat)) Then total(cat) = total(cat) + 1 ' key exists — bump it Else total(cat) = 1 ' first time — assigning creates the key End IfEnd Forall
Forall n In total Print ListTag(n) & ": " & n ' ListTag = the key, n = the valueEnd ForallThat’s the List in full. Keyed write creates or updates; IsElement tests existence; ForAll walks it and ListTag recovers the key. There’s no count, no sort, no keys() collection — a List is deliberately minimal — but for “accumulate something per key” it replaces a whole block of parallel-array bookkeeping with four lines, and the keyed access doesn’t get slower as the number of keys grows the way a linear array scan does.
Where it earns its place
Three shapes come up constantly and all collapse to a List:
- A “seen” set — dedup by assigning
seen(key) = Trueand testingIsElement(seen(key)); the value is irrelevant, the key is the whole point. - A counter / grouper — the example above, one running total per key.
- A lookup table — read a code list once into
label(code) = text, then resolve in-loop from memory instead of a repeated view hit (the same instinct behind caching an@DbLookup, but under your control).
Any time you catch yourself writing “does this key already exist” against an array, that’s a List.
The two gotchas
Reads have no default. This trips people coming from JavaScript objects or Notes items, where a missing thing reads as empty. A List tag that was never assigned isn’t empty — it’s absent, and referencing it for a read is a runtime error. So the IsElement check isn’t optional politeness; it’s the guard that keeps a read from throwing. Write-then-read is safe; read-before-write needs IsElement.
Tag case sensitivity is a module setting, not a fixed rule. The docs are explicit: “List tags can be case sensitive or case insensitive, depending on the setting for case sensitivity in the module,” and Option Compare is what decides. So total("AB") and total("ab") are two keys in one module and the same key in another — a portability landmine when you paste code between script libraries with different Option Compare settings. The safe habit is to normalise keys yourself (LCase(cat)) so the List’s behaviour doesn’t depend on a directive three screens up.
What about Java and SSJS?
There’s no Domino class here — the List is a language feature, so relatedJava and relatedSsjs are empty. But the concept is the most portable thing in this whole series: the List is exactly what Java calls a HashMap and what SSJS / JavaScript calls a plain object or a Map. If you’re moving keyed-collection logic out of LotusScript, you’re not looking for a Notes class — you’re reaching for the target language’s built-in map, which has the richer API (a size, a key set, ordering) that the List deliberately lacks. Going the other way, the lesson is the one this post is really about: before you build a hashmap out of parallel arrays in LotusScript, remember the language already has one.