List and Dictionary data types advanced-Business Central

 local procedure TestListAssignment()

var i: Integer; ListNumberOne: List of [Integer]; ListNumberTwo: List of [Integer]; begin for i := 1 to 20 do ListNumberOne.Add(i); ListNumberTwo := ListNumberOne; ListNumberTwo.Add(21); Message('List1 count: %1\List2 count: %2', ListNumberOne.Count(), ListNumberTwo.Count()); end

local procedure TestListShallowCopy()
var
    i: Integer;
    ListNumberOne: List of [Integer];
    ListNumberTwo: List of [Integer];
begin
    for i := 1 to 20 do
        ListNumberOne.Add(i);

    ListNumberTwo := ListNumberOne.GetRange(1, ListNumberOne.Count());

    ListNumberTwo.Add(21);

    Message('List1 count: %1\List2 count: %2', ListNumberOne.Count(), ListNumberTwo.Count());
end;


In the case of nested lists, we must use deep copy:
local procedure TestNestedListShallowCopy()
var
    ListNumberOne: List of [List of [Integer]];
    ListNumberTwo: List of [List of [Integer]];
    NestedList: List of [Integer];
    i: Integer;
    k: Integer;
begin
    //ListNumberOne will contain 25 NestedList, Nested list contain numbers from 6 to 10 (5 in total)
    for k := 6 to 10 do begin
        NestedList.Add(k);
        for i := 1 to 5 do
            ListNumberOne.Add(NestedList);
    end;

    //Shallow copy ListNumberOne to ListNumberTwo
    ListNumberTwo := ListNumberOne.GetRange(1, ListNumberOne.Count());

    //Additional number to Nested List will be displayed in ListNumberOne and ListNumberTwo as well
    NestedList.Add(11);

    //Result is 6 and 6 (6..11), because nested list is updated in previous step (we just check first nested list by index 1)
    Message('NestedList1 count: %1\NestedList2 count: %2',
        ListNumberOne.Get(1).Count(),
        ListNumberTwo.Get(1).Count());
end;

local procedure TestNestedListDeepCopy()
var
    ListNumberOne: List of [List of [Integer]];
    ListNumberTwo: List of [List of [Integer]];
    NestedList: List of [Integer];
    i: Integer;
    k: Integer;
begin
    //ListNumberOne will contain 25 NestedList, Nested list contain numbers from 6 to 10 (5 in total)
    for k := 6 to 10 do begin
        NestedList.Add(k);
        for i := 1 to 5 do
            ListNumberOne.Add(NestedList);
    end;

    //Deep copy ListNumberOne to ListNumberTwo
    foreach NestedList in ListNumberOne do
        ListNumberTwo.Add(NestedList.GetRange(1, NestedList.Count()));

    //Additional number to Nested List will be displayed in ListNumberOne only
    NestedList.Add(11);

    //Result is 6 and 5 because ListNumberTwo contain a new copy of nested list (it was same reference in shallow copy)
    Message('NestedList1 count: %1\NestedList2 count: %2',
        ListNumberOne.Get(1).Count(),
        ListNumberTwo.Get(1).Count());
end;

How can we use a list? For example, we need to collect all unique Customer No. values from Sales Orders. Then the code might look something like this:
local procedure CollectUniqueCustomerNoFromSalesOrder()
var
    SalesHeader: Record "Sales Header";
    ListOfCustomerNo: List of [Code[20]];
    CustomerNo: Code[20];
begin
    SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
    if SalesHeader.FindSet() then
        repeat
            //Collect unique entries
            if not ListOfCustomerNo.Contains(SalesHeader."Sell-to Customer No.") then
                ListOfCustomerNo.Add(SalesHeader."Sell-to Customer No.");
        until SalesHeader.Next() = 0;

    //Read and show each enique Customer No.
    foreach CustomerNo in ListOfCustomerNo do
        message(CustomerNo);
end;


local procedure CollectSalesInvoiceDocNoLineNoDict()
var
    SalesHeader: Record "Sales Header";
    SalesLine: Record "Sales Line";
    SalesInvoiceDocNoLineNoDict: Dictionary of [Code[20], List of [Integer]];
    ListOfLineNo: List of [Integer];
    LineNo: Integer;
    ResultTxt: TextBuilder;
    DocumentNo: Code[20];
begin
    SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Invoice);
    if SalesHeader.FindSet() then
        repeat

            //Clear list of Line No. for each new Sales Invoice
            Clear(ListOfLineNo);
            SalesLine.SetRange("Document Type", SalesHeader."Document Type");
            SalesLine.SetRange("Document No.", SalesHeader."No.");
            if SalesLine.FindSet() then
                repeat
                    //Collect Line No. of current Sales Invoice
                    ListOfLineNo.Add(SalesLine."Line No.");
                until SalesLine.Next() = 0;

            //Add DocumentNo with list of Line No. to dictionary
            SalesInvoiceDocNoLineNoDict.Add(SalesHeader."No.", ListOfLineNo);

        until SalesHeader.Next() = 0;

    //Read result and save it to text
    foreach DocumentNo in SalesInvoiceDocNoLineNoDict.Keys() do begin
        SalesInvoiceDocNoLineNoDict.Get(DocumentNo, ListOfLineNo);

        ResultTxt.AppendLine(DocumentNo);
        foreach LineNo in ListOfLineNo do
            ResultTxt.AppendLine(Format(LineNo));

        ResultTxt.AppendLine();
    end;

    Message(ResultTxt.ToText());
end;

local procedure GroupPOCustItemDict()
var
    PurchaseHeader: Record "Purchase Header";
    PurchaseLine: Record "Purchase Line";
    POCustItemDict: Dictionary of [Code[20], Dictionary of [Code[20], List of [Code[20]]]];
    DocumentNoItemNoDict: Dictionary of [Code[20], List of [Code[20]]];
    PrevDocumentNoItemNoDict: Dictionary of [Code[20], List of [Code[20]]];
    PrevDocNo: Code[20];
    ListOfItemNo: list of [Code[20]];
    VendorNo: Code[20];
    DocumentNo: Code[20];
    ItemNo: Code[20];
    ResultTxt: TextBuilder;
begin
    PurchaseHeader.SetCurrentKey("Buy-from Vendor No.", "No.");
    PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Order);
    if PurchaseHeader.FindSet() then
        repeat

            Clear(ListOfItemNo);
            PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
            PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
            PurchaseLine.SetRange(Type, PurchaseLine.Type::Item);
            if PurchaseLine.FindSet() then
                repeat
                    //Collect Item Nos. of current Purchase Document
                    ListOfItemNo.Add(PurchaseLine."No.");
                until PurchaseLine.Next() = 0;

            //Store current DocumentNo with list of document items
            Clear(DocumentNoItemNoDict);
            DocumentNoItemNoDict.Add(PurchaseHeader."No.", ListOfItemNo);

            //Check if current vendor group is exist
            if not POCustItemDict.ContainsKey(PurchaseHeader."Buy-from Vendor No.") then
                //Add new Vendor group with DocumentNo -> Item Nos. dictionary
                POCustItemDict.Add(PurchaseHeader."Buy-from Vendor No.", DocumentNoItemNoDict)
            else begin
                //Get previous DocumentNo -> Item Nos. dictionary
                POCustItemDict.Get(PurchaseHeader."Buy-from Vendor No.", PrevDocumentNoItemNoDict);

                //Read previous dictionary and add entries to current DocumentNo -> ItemNos dictionary
                foreach PrevDocNo in PrevDocumentNoItemNoDict.Keys() do
                    DocumentNoItemNoDict.Add(PrevDocNo, PrevDocumentNoItemNoDict.Values().Get(1));

                //Set total dictionary to current Vendor group
                POCustItemDict.Set(PurchaseHeader."Buy-from Vendor No.", DocumentNoItemNoDict);
            end;

        until PurchaseHeader.Next() = 0;

    //Read result and save it to text
    foreach VendorNo in POCustItemDict.Keys() do begin

        ResultTxt.AppendLine(StrSubstNo('%1:%2', PurchaseHeader."Buy-from Vendor No.", VendorNo));
        POCustItemDict.Get(VendorNo, DocumentNoItemNoDict);

        foreach DocumentNo in DocumentNoItemNoDict.Keys() do begin

            ResultTxt.AppendLine(StrSubstNo('--%1:%2', PurchaseHeader.FieldCaption("No."), DocumentNo));
            DocumentNoItemNoDict.Get(DocumentNo, ListOfItemNo);
            foreach ItemNo in ListOfItemNo do
                ResultTxt.AppendLine(StrSubstNo('----%1:%2', PurchaseLine.FieldCaption("No."), ItemNo));

        end;

        ResultTxt.AppendLine();
    end;

    Message(ResultTxt.ToText());
end;





No comments:

Post a Comment