As many Salesforce Apex programmers know, in Salesforce it’s pretty much an unchallenged best practice that all code should be able to handle bulk inserts, updates, etc. When adhering to this best practice, it’s really common to use sets, or lists as parameters in functions. Sometimes, there’s a need to convert between lists, or sets, or maybe even maps.
What’s the Difference between Sets and Lists?
Apex uses a hash structure for all sets. The fundamental differences between sets and lists is that a Set is unordered and unique. To access elements in a set, you must iterate through all of the items.
So, you can not do code like this:
Set sStrings = new Set; String bString = sStrings[1];
Instead, your code must do something like this:
Set sStrings = new Set; string bString = null; for (String s : sStrings) < if (s == 'b') < bString = 'b'; >> system.assertEquals('b',bString);
For a list, either method would be perfectly acceptable.
Why convert from a Set to List, or List to Set?
I use Sets anytime I want to ensure that my items are unique or when I need to check for the existence of an item in the collection.
Converting from a List to Set, can be done using the set’s constructor.
List lStrings = new List; Set sStrings = new Set(lStrings);
Converting from a Set to a List, can be done using the List constructor.
Set sStrings = new Set; List lStrings = new List(sStrings);
Both types of collections also have an addAll method that can be used to add items to an already existing collection.
There’s also, some pretty cool tricks to add the Ids of an element to a Set if you want to check if you have already processed an item or something like that.
For an example, let’s say I’ve queried some accounts and need their Ids for some processing. One way to do this, would be to loop through all of the accounts and add them to a set, but there’s a much easier way of doing this.
Using the for each approach:
List accounts = [select Id, Name from Account]; Set ids = new Set(); for (Account acc : accounts) < ids.add(acc.Id); >doSomethingWithIds(ids);
That approach is fine, but it can really start to add up over time. Instead, why not take advantage of the map and it’s methods.
Here’s an example that takes a List of Accounts, and casts it to a Set of Ids. I would never query an object and then on the next line get it’s list of Ids, this way.
Instead I would likely be doing some kind of filtering on the list in another method or something and then building a set of the Ids.
List accounts = [select Id, Name from Account]; Set ids = (new Map(accounts)).keySet().clone(); doSomethingWithIds(ids);
The above code is taking the List of Accounts, we just queried and casting it into a Map. keySet() then returns the Ids of the map, and then finally .clone() is so we can modify the set of Ids. Otherwise, we would get an exception thrown about the set not being modifiable.