D365 Business Central : List Data Type

List Data Type is an unbounded, strongly typed list of ordered objects that can be accessed by index. It serves as a replacement for arrays. Unlike traditional arrays, Lists provide dynamic and unlimited capacity, eliminating the need to declare dimensions upfront.

When creating a List, you specify using List of [DataType], such as List of [Integer] or List of [Text[20]]. However, List supports only simple data types like Integer, Text, and Code. Complex data types such as Blob, Record, Report, or Variant are excluded. Nevertheless, it is possible to store Lists within a List, allowing for nested list.

procedure NestedListSample()
var
    IntegerList: List of [Integer];
    NestedList: List of [List of [Integer]];
begin
    IntegerList.Add(1);
    IntegerList.Add(2);
    NestedList.Add(IntegerList);
end;

Why List?

Consider a scenario where you need to store a list of unique item numbers in a Sales Line. Traditionally, you might use a temporary table to accomplish this. However, utilising a List provides a cleaner and more readable solution. Here’s a code sample showcasing the difference:

//Use Temporary Item record
procedure GetItemNoFromSalesLine(SalesLine: Record "Sales Line"; var TempItem: Record Item temporary)
begin    
    SalesLine.FindSet();
    repeat
        if not TempItem.Get(SalesLine."No.") then begin
            TempItem.Init();
            TempItem."No." := SalesLine."No.";
            TempItem.Insert();
        end;
    until SalesLine.Next() = 0;
end;

//Using List
procedure GetItemNoFromSalesLine(SalesLine: Record "Sales Line"; var ItemList: List of [Code[20]])
begin    
    SalesLine.FindSet();
    repeat
        if not ItemList.Contains(SalesLine."No.") then
            ItemList.Add(SalesLine."No.");
    until SalesLine.Next() = 0;
end;

While temporary tables remain a viable option, the List data type offers a simpler and more efficient approach for storing simple data structures. Its built-in methods for storing, searching, and manipulating data make it especially powerful for specific tasks.

Special Characteristics

  • Lists maintain the order in which elements are added, ensuring that the sequence is preserved. When appending new elements, they are placed at the end of the List. This inherent property is valuable when you need to preserve the sequence of items.
procedure ListSequenceSample()
var
    FruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.Add('Apple');
    FruitList.Add('Orange');
    FruitList.Add('Apple');

    foreach Fruit in FruitList do
        Message(Fruit); //Result in Apple, Orange, Apple
end;
  • Lists uses 1-based indexing, meaning Lists are always indexed from 1.
procedure GetFirstIndexSample()
var
    ItemList: List of [Code[20]];
begin
    ItemList.Add('A');
    ItemList.Add('B');
    Message(ItemList.Get(1)); //Result is A
end;
  • Because List is based on Index, it can store duplicate values. Although possible, it is commonly used to store unique values.
procedure StoreDuplicateValuesSample()
var
    FruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.Add('Apple');
    FruitList.Add('Apple');
    FruitList.Add('Apple');

    foreach Fruit in FruitList do
        Message(Fruit); //all results in Apple
end;
  • The foreach loop is used to iterate over each element in a List
procedure LoopSample()
var
    FruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.AddRange('Apple', 'Banana', 'Orange');

    foreach Fruit in FruitList do
        Message(Fruit);
end;
  • Lists are reference types, meaning they are always passed by reference, regardless of whether the parameter is specified as a value or reference.
procedure PassReferenceSample()
var
    FruitList: List of [Text];
    FruitList2: List of [Text];
    Fruit: Text;
begin
    FruitList.AddRange('Apple', 'Banana', 'Pineapple', 'Mango', 'Grapes');

    FruitList2 := FruitList; //pass by reference

    DeleteApple(FruitList);

    foreach Fruit in FruitList do
        Message(Fruit); //Result in Banana, Pineapple, Mango, Grapes

    foreach Fruit in FruitList2 do
        Message(Fruit); //Also result in Banana, Pineapple, Mango, Grapes
end;

procedure DeleteApple(FruitList: List of [Text]) //pass by reference without specifying var
begin
    FruitList.Remove('Apple'); //because it always passes by reference, the original list will be modified as well
end;

Method

List data type provides some built-in methods. Let’s explore some of the commonly used methods:

Add

Appends a value to the end of the List.

procedure AddSample()
var
    FruitList: List of [Text];
begin
    FruitList.Add('Apple');
    FruitList.Add('Banana');
end;

AddRange

Appends multiple values to the end of the List.

procedure AddRangeSample()
var
    FruitList: List of [Text];
begin
    FruitList.AddRange('Apple', 'Banana', 'Orange');
end;

Contains

Checks if an element exists in the List.

procedure ContainsSample()
var
    FruitList: List of [Text];
begin
    FruitList.AddRange('Apple', 'Banana', 'Orange');

    if FruitList.Contains('Banana') then
        Message('Banana is in the list');
end;

Count

Retrieves the number of elements in the List.

procedure CountSample()
var
    FruitList: List of [Text];
begin
    FruitList.AddRange('Apple', 'Banana', 'Orange');

    Message('Fruit Count %1', FruitList.Count());
end;

Get

Retrieves the element at a specified index. This method will raise an error if the index is outside the valid range.

procedure GetSample()
var
    FruitList: List of [Text];
begin
    FruitList.AddRange('Apple', 'Banana', 'Orange');

    Message('Second Index %1', FruitList.Get(2));
    Message('Fourth Index %1', FruitList.Get(4)); //Result in error An invalid argument was passed to a 'List' data type method
end;

GetRange

Retrieves a range of elements as a new List.

procedure GetRangeSample()
var
    FruitList: List of [Text];
    OtherFruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.AddRange('Apple', 'Banana', 'Orange', 'Pineapple', 'Mango', 'Grapes', 'Watermelon', 'Strawberry', 'Kiwi');

    OtherFruitList := FruitList.GetRange(2, 5); //Get 5 items starting from index 2

    foreach Fruit in OtherFruitList do
        Message(Fruit); //Result in Banana, Orange, Pineapple, Mango, Grapes
end;

IndexOf

Searches for the first occurrence of a value and returns its index.

procedure IndexOfSample()
var
    FruitList: List of [Text];
    Index: Integer;
begin
    FruitList.AddRange('Apple', 'Banana', 'Apple', 'Pineapple', 'Mango');

    Index := FruitList.IndexOf('Apple');

    Message('Index of Apple %1', Index); //Result in 1
end;

LastIndexOf

Searches for the last occurrence of a value and returns its index.

procedure LastIndexOfSample()
var
    FruitList: List of [Text];
    Index: Integer;
begin
    FruitList.AddRange('Apple', 'Banana', 'Apple', 'Apple', 'Mango');

    Index := FruitList.LastIndexOf('Apple');

    Message('Last Index of Apple %1', Index); //Result in 4
end;

Remove

Removes the first occurrence of a specified value from the List. Returns true if item is successfully removed; otherwise, false. This method also returns false if item was not found in the List.

procedure RemoveSample()
var
    FruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.AddRange('Apple', 'Banana', 'Apple', 'Apple', 'Mango');

    FruitList.Remove('Apple');

    foreach Fruit in FruitList do
        Message(Fruit); //Result in Banana, Apple, Apple, Mango

    Message('%1', FruitList.Remove('Kiwi')); //Result in false
end;

Reverse

Reverses the order of elements in the List.

procedure ReverseSample()
var
    FruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.AddRange('Apple', 'Banana', 'Pineapple', 'Mango', 'Grapes');

    FruitList.Reverse();

    foreach Fruit in FruitList do
        Message(Fruit); //Result in Grapes, Mango, Pineapple, Banana, Apple
end;

Set

Modifies the element at a specified index. The index must be within current index range.

procedure SetSample()
var
    FruitList: List of [Text];
    Fruit: Text;
begin
    FruitList.AddRange('Apple', 'Banana', 'Pineapple', 'Mango', 'Grapes');

    FruitList.Set(3, 'Orange');

    foreach Fruit in FruitList do
        Message(Fruit); //Result in Apple, Banana, Orange, Mango, Grapes

    FruitList.Set(6, 'Kiwi'); //Result in error An invalid argument was passed to a 'List' data type method
end;

Summary

The List data type is a powerful tool that simplifies data storage, retrieval, and manipulation. By leveraging Lists, you can improve code readability and efficiency. Whether you choose to use temporary tables or Lists depends on the complexity of your data and the specific requirements of your application. However, understanding and utilising Lists will undoubtedly make you a better developer.

GitHub link.

thatnavguy

Experienced NZ-based NAV Developer and Consultant with 15+ years of experience leading multiple IT projects, performing business analyst, developing, implementing, and upgrading Dynamics NAV and Business Central. Passionate to deliver solution that focuses on user-friendly interface while keeping high standard of compliance with the needs.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *