0

I have the following bit of code which is a nested loop that I'd like to know if it can be replicated by using a map instead as I haven't used them before and would like to know how it would end up looking like and any performance gains.

//Creating the list that will hold all of the projects that will be created and linked to the relevant opportunities
List<Project__c> newProjects = new List<Project__c>();

//Copying in all of the fields from the previous Project into the new Projvect that has the auto renewed dates
for(Project__c npro : Project){
    for(Opportunity nopp : Opportunity){
        //nested loop to go over all Opportunities returned from the query and creating the identical projects
        if(npro.Related_Opportunity__c == nopp.Id){
            npro.Auto_Renewed__c = true;
            npro.Status__c = 'Completed';
            Project__c clonedproj = new Project__c();
            //List of fields that will be copied from the old project to the new project
            newProjects.add(clonedproj); 
        }
    }
}
insert newProjects;
update Project;

2 Answers 2

2

Whenever you have the for-for-if combination, as you do here, that's a prime candidate for the use of a map. In this case, it would approximately be:

//Creating the list that will hold all of the projects that will be created and linked to the relevant opportunities
List<Project__c> newProjects = new List<Project__c>();
Map<Id, Schema.Opportunity> opportunityById = new Map<Id, Schema.Opportunity>(Opportunity);
//Copying in all of the fields from the previous Project into the new Projvect that has the auto renewed dates
for(Project__c npro : Project){
    Opportunity relatedOpportunity = opportunityById.get(npro.Related_Opportunity__c);
    if(relatedOpportunity != null) {
        npro.Auto_Renewed__c = true;
        npro.Status__c = 'Completed';
        Project__c clonedproj = new Project__c();
        newProjects.add(clonedproj);
    }
}
insert newProjects;
update Project;

As far as performance is concerned, if the size of Opportunity is 1, then the algorithm you have is the same as the one above. However, this is when we can talk about Big-O notation, which explains the time cost associated with a given algorithm.

In general, we have the following classes of algorithms:

Big-O Meaning Example
O(1) The algorithm takes a fixed amount of time. Access the index of an array: myArray[index].
O(logx) The algorithm is better than linear growth. A binary search.
O(n) The algorithm has linear growth. A for loop over a list of elements.
O(nx) The algorithm has exponential growth. A nested for loop.

Ideally, we want O(1) time algorithms, though most algorithms in Apex will be no better than O(n), since we want to iterate through every element.

Imagine your original code is given a list of 200 projects and 200 opportunities. That results in 200 × 200 (or 2002) executions of the if statement, a total of 40,000 if statements executed. This is O(n2) performance. The algorithm above results in a O(n) × O(1) or just O(n) performance. In other words, for a list of 200 elements, the Map approach will be approximately 200 times faster in performance. To put it in concrete numbers, imagine the map version takes about 1 second, your original code would complete in about 200 seconds. Actual performance may vary, but you can expect loops like then one you've written to approach the governor limit of 10,000ms (10 seconds) with even a modest amount of data.

Not all nested for loops are bad; sometimes you really do need to iterate over every outer and inner child in a dataset, such as multiplying two matrixes. As a developer, it's important to understand which algorithm is the correct algorithm for a given use case, and that comes with experience and research.

0

You can check the following:

//Creating the list that will hold all of the projects that will be created and linked to the relevant opportunities
List<Project__c> newProjects = new List<Project__c>();

Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>(Opportunity);

//Copying in all of the fields from the previous Project into the new Project that has the auto renewed dates
for(Project__c npro : Project){            
        if(oppMap.containsKey(npro.Related_Opportunity__c)){
            npro.Auto_Renewed__c = true;
            npro.Status__c = 'Completed';
            Project__c clonedproj = new Project__c();
            //List of fields that will be copied from the old project to the new project
            newProjects.add(clonedproj); 
        }
}

insert newProjects;
update Project;

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .