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.
1 2 3 4 5 6 7 8 9 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //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.
1 2 3 4 5 6 7 8 9 10 11 12 | 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.
1 2 3 4 5 6 7 8 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 | 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
1 2 3 4 5 6 7 8 9 10 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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.
1 2 3 4 5 6 7 | 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.
1 2 3 4 5 6 | procedure AddRangeSample() var FruitList: List of [Text]; begin FruitList.AddRange('Apple', 'Banana', 'Orange'); end; |
Contains
Checks if an element exists in the List.
1 2 3 4 5 6 7 8 9 | 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.
1 2 3 4 5 6 7 8 | 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.
1 2 3 4 5 6 7 8 9 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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.
1 2 3 4 5 6 7 8 9 10 11 | 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.
1 2 3 4 5 6 7 8 9 10 11 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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.