Exploring The Power of Sets — Swift 3.0

The three primary collection types in Swift are arrays, dictionaries, and sets. Those of you who have some experience using arrays and dictionaries have come across both the power and limitations of using each. In this post I will be focusing on sets for it’s ability to gather information from our collection in an easy and efficient way.

What Are sets?

Sets are a collection type in Swift that store distinct values of the same type in an unordered collection. Keyword: distinct. Similar to Swift’s other two collection types, arrays and dictionaries, sets are useful for storing and organizing data in an efficient way while maintaining its unique characteristics that allow for certain types of functionality.

When declaring a set, the type must be hashable, meaning that if you are using a custom type, it must conform to the Hashable protocol. Types like String, Int, Double, and Bool are already hashable by default so they do not need any modification.

So how do you create a set you may ask? Easy!

First lets start with the syntax. When creating a Swift type set, the proper syntax is Set<Element> . Element represents the type that will be stored in the set.

Here is an example of how we can initialize and create a set:

It is important to note that the Swift compiler cannot infer a type set as it does with an array. This means that the type should always be included when creating the instance of a set.

Since part of the working definition for sets include their ability to only store unique values, we can compare what our code would look like when adding duplicate values into an array vs. a set.

An array can hold multiple values and doesn’t concern itself with distinct values like so:

A set on the other hand highlights the importance of holding unique values and will not add a value if it is not distinct.

Now picture yourself trying to populate a collection type with a method that generates random values, and you don’t want duplicates. Wouldn’t a set be a convenient way of combating this problem?


In addition to storing unique values, sets can also perform a series of operations that are specific to this type.

This includes:

.intersection(_:)
.symmetricDifference(_:)
.union(_:)
.subtracting(_:)

Now suppose we were having guests over for dinner and we decided to bake a cake and brownies for dessert. Here is some working code illustrating these operations in action.

We can perform the .intersection(_:) method to create a set containing the values that are found in both sets, like so:

The .symmetricDifference(_:) method creates a set that holds the values that are unique to each set.

The .union(_:) method creates a set that combines the values in both sets without storing any duplicates.

If we wanted to create a shopping list of the ingredients needed for both our cake and brownies, our code would look like this:

Lastly, the .subtracting(_:) method creates a set with values that are not in the specified set.

Membership and Equality

In addition to performing the operations mentioned above we are also able to check set membership and equality. Apple’s documentation describes what this means in the diagram below:

The illustration below depicts three sets — a, b and c—with overlapping regions representing elements shared among sets. Set a is a superset of set b, because a contains all elements in b. Conversely, set b is a subset of set a, because all elements in b are also contained by a. Set b and set c are disjoint with one another, because they share no elements in common.
The Swift Programming Language (Swift 3) — Set Membership and Equality

Following Apple’s example on the documentation, lets say we have the following sets, can anyone guess which is the superset and subset?

let houseAnimals: Set = ["dog", "cat"]
let farmAnimals: Set = ["cow", "chicken", "sheep", "dog", "cat"]
let cityAnimals: Set = ["pigeon", "mouse"]

If you can’t, don’t worry, there’s a method for that!

The methods that are associated with set membership and equality are:

==
.isSubset(of:)
.isSuperset(of:)
.isStrictSubset(of:) or isStrictSuperset(of:)
.isDisjoint(with:)

What makes these methods different from the operations mentioned above is that they return a Bool statement describing the status of each set.

For example, if we wanted to check if two sets were equal we would use the == operator.

Or, if we wanted to check if farmAnimals was a superset of houseAnimals, we would simply write this:

Similarly, the .isSubset(of:) method would tell us whether all the values in the set are contained in a specified set. An example of this would be:

Like the .isSuperset(of:) and .isSubset(of:) method, the isStrictSubset(of:) and isStrictSuperset(of:) tells us whether a set is a superset or subset, but only if it is not equal to the specified set.

Lastly, the .isDisjoint(with:) determines whether the two sets have values in common.

Conclusion

Sets can be a great tool if you’re looking to work with distinct values and don’t care about the order of the collection. Not to mention that the operations and methods that are accessible to sets can save you tons of lines of code relative to using a different type of collection method to gather specific information about your values.

Don’t believe me? Try it out yourself! You have all the tools to get started, and if you want some extra information, take a look at the resources down below :)

Resources

Swift Documentation

Stack Overflow

Coding Explorer Blog — Swift Set Type