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.