Set in Swift, the forgotten Type
Set in one of a primary value type provided by Objective-C and Swift (along with almost every programming language). It is however under-utilized by the Cocoa Framework itself, most likely due to framework evolutions that needed to be backward compatible with the previous decision of Apple to use Arrays instead.
Swift however has come a long way in making Set easily usable, especially with their new syntax and some easy-to-use new operators.
What is a Set?
A Set is an unordered collection of unique elements. It is perfectly filling the gap left by the more well-known and used Arrays and Dictionaries. Let’s compare what each type primary goal is:

Arrays:
They are one of the most commonly used data type in app development. This value type (in swift) is an ordered, random-access collection. This means that you can access any part of the collection with a O(1) complexity by using indexes. Arrays are allowing any types to be stored in the collection.

Dictionaries :
Type of hash table providing fast access to the entries it contains. A dictionary allows associating a Key (Hashable) to a Value. The data stored in the collection is unordered, and each Key can only associate a single value.

Sets:
Sets are an unordered collection of unique Elements (Hashable). The use cases where a Set type excels are when you need to test efficiently for membership, or when you need to ensure a value only appears once in a collection.

In-depth look at the Set Type.
Set in a collection, that can contain none to multiple data values in an unordered fashion. The type guarantees that each value contained will only be contained once (thus the Hashable Requirement). The unordered part of the definition is rather important as it means that you will not be able to access elements in the same order they were added and runtime doesn’t give any guarantee as to the positioning of any element.
One interesting thing to note is that Swift chose to require Hashable conformance, instead of just Equatable protocol, as this is enabling the framework to heavily optimize both storage, comparison, access, and search. Swift makes it very easy to conform to this protocol as the compiler automatically generates conformances and implementation if the type used only contains hashable properties already.
Declaration and basic operations on the instance:
Here is a sample with a couple of different ways to declare Sets. Let’s take a closer look.
Swift is making it very easy to declare a set and is using a very similar syntax to the Array inline declaration. Notice that it’s almost the same except that we are specifying the type next to the variable name.
On line 3, we are specifying the Element template type, making it a bit easier for the compiler to infer the type. This allows for a faster compile time as the compiler doesn’t need to look at our declaration to determine the template type for this variable.
On line 4, we can see that this is not mandatory and that the compiler can also do it by itself, of course at the cost of a longer compile time. I don’t recommend it for larger projects as this can make a huge difference.
On line 9, you can see that it’s also possible to mix different Hashable types in the same container by leveraging the AnyHashable type. However, in this case, you have to specify the template type or the compiler would give you an error.
Let’s now interest ourselves in the console output. Line 6, 7 and 11 might print the following:
[3, 1, 9, 7, 5]
["no", "maybe", "yes", "I do know"]
[AnyHashable("Hello"), AnyHashable(2), AnyHashable(1)]
There are two things to notice here.
- I used “Might print”. Remember, Set is an unordered collection, so your result might differ. You can even see it by running this sample multiple times in the playground, numbers are moving around.
- Line 3 and 4 had duplicate values in their declaration. They are now missing from the output, highlighting the “unique” trait of the type definition
For the usage, Set is part of the Collection category of type. Collections are all using the same kind of methods to access and iterate over their type. The two method above provide a way to loop over the Set. However, the line 9 way is preferred as it’s closer to functional programming vs the line 5 way is more iterative, and Swift is trying to move closer to the functional paradigm. You can also most of the methods and properties from the Array type you know and love like
func first(where: (Element) -> Bool) -> Element?func min() -> Element?func max(by: (Element, Element) -> Bool) -> Element?func map<T>((Element) -> T) -> [T]func compactMap<ElementOfResult>((Element) -> ElementOfResult?) -> [ElementOfResult]func sorted() -> [Element]var isEmpty: Boolvar count: Intfunc contains(Element) -> Bool
and more…
To add or remove items from a set, you can use


Notice that inserting and removing operations are mutating, requiring a var instead of a let declaration of the variable.
Combining Sets
Now that we are comfortable with the basics of type let’s take it to the next level, where the real power of Set really is. Set operations.

You can create new sets based of 2 Sets by using the methods above. Each method will use different items of the two collections based on the method you choose to use.
- Use the
intersection(_:)
method to create a new set with only the values common to both sets. - Use the
symmetricDifference(_:)
method to create a new set with values in either set, but not both. - Use the
union(_:)
method to create a new set with all of the values in both sets. - Use the
subtracting(_:)
method to create a new set with values not in the specified set.
Comparing Sets

- Use the “is equal” operator (
==
) to determine whether two sets contain all of the same values. - Use the
isSubset(of:)
method to determine whether all of the values of a set are contained in the specified set. - Use the
isSuperset(of:)
method to determine whether a set contains all of the values in a specified set. - Use the
isStrictSubset(of:)
orisStrictSuperset(of:)
methods to determine whether a set is a subset or superset, but not equal to, a specified set. - Use the
isDisjoint(with:)
method to determine whether two sets have no values in common.
Real-Life Use Cases
- Remove users that have less than X and more than Y credit on their account from a list of users
- Find the list of users that are both following account A and account B on a social network
- Find people that like blue or red, but not both
Reference: Apple Set Documentation