Erik's ToolBox Documentation
Index

Collections: List and Dictionary

ToolBox supports the generic collection types List of [Type] and Dictionary of [KeyType, ValueType]. Unlike arrays, collections grow and shrink dynamically, and you iterate them with the foreach statement.

List of [Type]

A List is an ordered, dynamically sized collection of elements of one type. Lists are 1-based: the first element is at index 1.

Declaration

var
    Names: List of [Text];
    Amounts: List of [Decimal];
    Numbers: List of [Integer];
    Tokens: List of [JsonToken];

The element type can be any scalar type (Text, Code, Integer, BigInteger, Decimal, Boolean, Date, Time, DateTime, Duration, Guid, Char, Byte, Option, ...) or one of the four JSON types. Record, Dialog, and nested collections (List of [List of [Text]]) are not allowed as elements. A size on the element type (List of [Text[50]]) is accepted but not enforced.

Members

Member Returns Description
add(Value) Append an element
count() Integer Number of elements
contains(Value) Boolean Whether the value is present
get(Index) element 1-based; errors when out of range
get(Index, var Value) 1-based; fills the variable
getrange(Index, Count) List 1-based sublist
indexof(Value) Integer 1-based position; 0 when not found
lastindexof(Value) Integer 1-based position of the last match; 0 when none
insert(Index, Value) 1-based insert
remove(Value) Boolean Removes the first occurrence
removeat(Index) 1-based remove
set(Index, Value) 1-based; replace an element
reverse() Reverse the list in place
addrange(FromList) Append all elements of another list

Example

var
    Fruits: List of [Text];
    Fruit: Text;
    First: Text;
begin
    Fruits.Add('Apple');
    Fruits.Add('Banana');
    Fruits.Add('Cherry');

    Message('Count: %1', Fruits.Count());        // 3
    Message('Position of Banana: %1', Fruits.IndexOf('Banana')); // 2

    Fruits.Get(1, First);
    Message('First: %1', First);                 // Apple

    Fruits.Reverse();
    foreach Fruit in Fruits do
        Message('Fruit: %1', Fruit);             // Cherry, Banana, Apple
end;

Dictionary of [KeyType, ValueType]

A Dictionary maps keys to values. Each key is unique. Keys are matched by their text- formatted value, so two keys that format to the same text are considered the same key.

Declaration

var
    Prices: Dictionary of [Text, Decimal];
    Counts: Dictionary of [Code, Integer];

The key type must be one of Text, Code, Integer, BigInteger, Option, Boolean, Guid, Date, Time, DateTime, or Decimal. The value type follows the same rules as a List element type (any scalar or JSON type; no records, dialogs, or nested collections).

Members

Member Returns Description
add(Key, Value) Errors when the key already exists
set(Key, Value) Add or replace
containskey(Key) Boolean Whether the key is present
count() Integer Number of entries
get(Key) value Errors when the key is missing
get(Key, var Value) Fills the variable
remove(Key) Boolean Removes the entry
keys() List All keys as a list
values() List All values as a list

Example

var
    Stock: Dictionary of [Text, Integer];
    ItemNo: Text;
    Qty: Integer;
    Keys: List of [Text];
begin
    Stock.Add('1000', 25);
    Stock.Add('1100', 40);
    Stock.Set('1000', 30);                       // replace existing value

    if Stock.ContainsKey('1100') then
        Message('1100 stock: %1', Stock.Get('1100'));

    Keys := Stock.Keys();
    foreach ItemNo in Keys do begin
        Stock.Get(ItemNo, Qty);
        Message('Item %1: %2 in stock', ItemNo, Qty);
    end;
end;

Iterating with foreach

The foreach statement iterates over a List (and over the results of methods such as Text.Split(), Dictionary.Keys(), Dictionary.Values(), and Regex.Split() that return a list), and over a JsonArray with a JsonToken loop variable.

Syntax

foreach <element> in <collection> do
    <statement>;

The loop variable's type must match the collection's element type. A Dictionary itself cannot be the subject of foreach; iterate its Keys() or Values() list instead.

var
    Csv: Text;
    Parts: List of [Text];
    Part: Text;
begin
    Csv := 'red,green,blue';
    Parts := Csv.Split(',');                     // Text.Split returns a List of [Text]
    foreach Part in Parts do
        Message('Color: %1', Part);
end;

Split must be called on a Text variable; a string literal cannot be the receiver of a method call (see Text Methods).

in as a keyword: foreach ... in ... uses in as part of the loop syntax. The same in word is also the set-membership operator (if X in [1, 3..5] then). ToolBox distinguishes them by context, so in is not otherwise reserved. See Control Flow.

Differences from Standard AL

  • Lists are 1-based in ToolBox, matching AL. (Note that JSON arrays are 0-based — see

Json Support.)

  • Dictionary keys are compared by their text-formatted value. This makes Code and Text

keys interoperate naturally but means numerically-distinct keys that format identically collide.

  • foreach over a Dictionary is not supported. Standard AL iterates the keys; in ToolBox

you iterate Keys() or Values() explicitly.

  • Lists and dictionaries are reference types, as in standard AL: assigning one variable to

another or passing it to a procedure shares the same collection. Clear(MyList) rebinds the variable to a new, empty collection.