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.