Apex: Converting Lists to Sets, and Sets To Lists

Sharing is Caring

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<String> sStrings = new Set<String>{'a','b','c','d','e'};

String bString = sStrings[1];

Instead, your code must do something like this:

Set<String> sStrings = new Set<String>{'a','b','c','d','e'};

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<String> lStrings = new List<String>{'a','b','c','d','e'};
Set<String> sStrings = new Set<String>(lStrings);

Converting from a Set to a List, can be done using the List constructor.

Set<String> sStrings = new Set<String>{'a','b','c','d','e'};

List<String> lStrings = new List<String>(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<Account> accounts = [select Id, Name from Account];
Set<Id> ids = new Set<Id>();

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<Account> accounts = [select Id, Name from Account];
Set<Id> ids = (new Map<Id,Account>(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.

Sharing is Caring

Brian is a software architect and technology leader living in Niagara Falls with 13+ years of development experience. He is passionate about automation, business process re-engineering, and building a better tomorrow.

Brian is a proud father of four: two boys, and two girls and has been happily married to Crystal for more than ten years. From time to time, Brian may post about his faith, his family, and definitely about technology.

6 Comments

  1. Tanuja

    Could you please explain me this
    (new Map(accounts)).keySet().clone();

    Thanks

    • Hi Tanuja,

      Thanks for taking the time to comment. I’ve updated the blog to clarify what’s being done.

      Basically, we’re taking advantage of the fact that we can pass in a List of SOQL objects and automatically use the Id as part of the Map, and then we grab the keySet() which is a set of Ids. And finally, .clone() is so that the list could be modifiable in the future.

  2. ChrisN

    Why wouldn’t you just do Map m = new Map([SELECT Id, LastName FROM Contact]); if you want the id’s in this example?

    • Hi Chris,

      Thanks for taking the time to comment.

      I would normally do that. My final example isn’t very good. I will think of a better example and update the post.

  3. Jeff Stevens

    Nice article.

    You could also do the lines of…
    List accounts = [select Id, Name from Account];
    Set ids = (new Map(accounts)).keySet().clone();

    doSomethingWithIds(ids);

    With….
    map mAccounts = new map([SELECT id,Name FROM Account]);
    doSomethingWithIds(mAccounts.keyset());

    • Hi Jeff,

      Thanks for taking the time to comment. My final example isn’t very good, and I would really hope that people wouldn’t take this approach to simply get a set of Ids.

      Also, you wouldn’t be able to do any kind of manipulation to the set if you pass in the keyset() without cloning it.

Comments are closed.