0

I am completely new to Apex programming and I don't know how to efficiently get values from the Map key. below is the example I need to check three different keys and based on the matching it should return the records. So I have created three new instances for Map to achieve this and if I want another check another set of the key then I need to create another instance which is not the best way of programming? please help me to overcome this issue?

       List<Company__c> CompanyList = [select id,Name,Size__c,from Company__c where id in:ProjectId];
  List<Opportunity> Opportunity = [Select id,Name,Size from Opportunity];
           
     map<string,Company__c> setOrdKey = new map<string,Company__c>();
     map<string,Company__c> setOrdSize = new map<string,Company__c>();
     map<string,Company__c> setOrdSize = new map<string,Company__c>();
    
    
    for(Company__c track :CompanyList)
                {
                    if(track.Name!= null)
                    {
                        setOrdKey.put(track.Id,track);
                        setOrdSize.put(track.Size__c,track);
                        setOrdName.put(track.Name,track);
                    }
                    
                }

for(integer i = 0; i < Opportunity.size(); i++) 
 {
    if(setOrdKey.containskey(Opportunity[i].Id) && setOrdSize.containskey(Opportunity[i].Size__c))
     {
                       System.debug('Size');
    }
    else if(setOrdKey.containskey(Opportunity[i].Name)
    {
      System.debug('Company');
    
    }
}
2
  • FYI you are comparing Company__c Id to Opportunity Id in your first setOrdKey map. That first if check will always return false. Jun 27, 2021 at 15:12
  • There's nothing wrong with multiple maps if you need them. As an example, since your first if statement is comparing both Id and Size, there's no need for two separate maps there (you can just concatenate the 2 values as a single map/key). To provide a better answer, you'd have to edit your question to provide what you're trying to achieve with this code as I assume you're hinting on more scenarios you need to check? Jun 27, 2021 at 15:25

1 Answer 1

2

Just a few quick points I'd like to mention:

  • Usually, people will use a plural variable name to act as a mental shortcut for "this is a collection" (a list, set, or map), or prepend/append List/Set/Map. So your Opportunity variable would be opportunities, opps, oppsList or something along those lines. It's not a requirement, but having a naming convention and sticking to it will help you (and others) remember what things are when you come back to it in the future
  • If you're iterating over a collection, it's easier to use the for(<type><variable name> :<collection>) syntax. Here, it would be for(Opportunity opp :Opportunity)

When you want to compare multiple fields at once, using an SObject as the key for a map (or the type of a Set) is a powerful tool.

The main thing you have to be aware of is that once you put an SObject instance into a Map (as the key) or into a Set, you do not want to make any changes to the same instance of that SObject. If you do, you won't be able to access the value that was associated to the key that you changed (it's just a part of how Maps and Sets work under the hood).

// In your situation, we can get by with a single map
Map<Company__c, Company__c> companyKeyToCompanyMap = new Map<Company__c, Company__c>();

for(Company__c comp :companyList){
    // You have two different criteria combinations that you want to check,
    //   so you'll create two keys
    // Each one must only contain the data you want to compare against
    // This approach is also very case-sensitive
    Company__c compKey1 = new Company__c(
      Name = comp.Name
    );

    Company__c compKey2 = new Company__c(
        Id = comp.Id,
        Size__c = comp.size
    );

    companyKeyToCompanyMap.put(compKey1, comp);
    companyKeyToCompanyMap.put(compKey2, comp);
}

for(Opportunity opp :oppList){
    // Now, you can use your second object to attempt to re-create the key for
    //   the map.
    // Note that every different SObject has a different prefix for the Id.
    // An Opportunity Id will never be the same as an Id for Account, Contact,
    //   My_Sobject__c, etc...
    Company__c testKey1 = new Company__c(
        Name = opp.Name
    );

    Company__c testKey2 = new Company__c(
        Id = opp.Company_Lookup__c,
        Size__c = opp.Size__c
    );

    if(companyKeyToCompanyMap.containsKey(testKey2)){
        // we have a match on the Id and Size
    }else if(companyKeyToCompanyMap.containsKey(testKey1)){
        // we have a match on the Name (but not Id and Size combined)
    }
}
3
  • I like to call my map variables using the patter valuesByKey, so if I have Account records in a map where the key is the Account ID, I call it accountsById. As to using SObject as a key, be careful to treat them as immutable (don't write to them) because it is a sure fire way to mess up your map if you modify an object used as a key. I take the approach of using Array<Object> when I want a compound key - they are very efficient (but again require careful treatment).
    – Phil W
    Jun 27, 2021 at 16:04
  • @PhilW I keep forgetting that they added a contains() method for Lists some time ago. I wonder if there's any performance difference between using it on a set vs on a list.
    – Derek F
    Jun 27, 2021 at 16:12
  • 2
    @DerekF List.contains() is O(n), it iterates over the whole list, while Set.contains() and Map.containsKey() are O(1)
    – RubenDG
    Jun 27, 2021 at 16:27

You must log in to answer this question.

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