Sets are one of Swift’s collection types. A set stores an amount of unique values, that have no particular order. You can imagine a set to be like a box of billiard balls: They are all unique in terms of color and number, but they don’t have a certain order inside the box.

*Hint: This post is using Swift 4 and Xcode 10*

Creating a set is very straightforward:

1 |
let setA: Set<String> = ["a","b","c"] |

In this example, a set called setA of strings has been created. It stores the values a, b and c. In contrast to an array, the elements are not ordered. By using type interference, the set can also be created like this:

1 |
let setB: Set = ["a","b","c"] |

It’s also possible to use the initialiser of the set type:

1 |
let setC = Set(["a","b","c"]) |

Like an array, a set is not mutable, if it’s declared as a constant by using let. For mutable sets, you can use the keyword var:

1 |
var setD = Set(["a","b"]) |

We will learn more about mutable sets later on.

You can access the values of a set by using a loop:

1 2 3 |
for value in setA { print(value) } |

Note that the order of the values in the loop can be different every time you run the code. From the outside it looks like they the values are picked randomly.

First of all, you can check whether a set is empty:

1 |
print(setA.isEmpty) |

Also the number of elements of a set can be checked:

1 |
print(setA.count) |

Both of these operations are also available for arrays. More typical for a set is the question, whether a certain element is a member of a set. For that, you can use the method contains:

1 |
print(setA.contains("a")) |

Mutable sets can be changed. You can add and remove values:

1 2 |
setD.insert("c") setD.remove("a") |

Since the values of a set are unique, a value can only be added once to the same set. The insert method can be called with the same values multiple times, but the set won’t change:

1 2 3 4 5 6 7 |
var setE: Set = [1,2,3,4] setE.insert(5) setE.insert(5) setE.insert(5) print(setE) //[4,5,1,2,3] |

As before, the order of the output can be different every time you run the code since sets are not ordered.

Sets can be compared. Obviously, comparing the equality of two sets is possible:

1 2 3 4 5 6 |
let setA: = [“a”, “b”, “c”] let setB: = [“a”, “b”, “c”] if setA == setB { print(“the sets are equal”) } |

In this case, the sets are equal.

There is no useful definition for a smaller and bigger comparison of two sets, but you can check whether a set is a subset of another set:

1 2 3 |
let intSetA: Set = [1,2,3,4,5,6,7,8,9,0] let intSetB: Set = [1,2,3] intSetB.isSubset(of: intSetA) //true |

It’s also possible to check whether it’s a strict subset. In that case, it has to be a subset but must not be equal:

1 2 3 4 5 6 7 8 |
let intSetA: Set = [1,2,3,4,5,6,7,8,9,0] let intSetB: Set = [1,2,3,4,5,6,7,8,9,0] let intSetC: Set = [3,4,5] intSetB.isSubset(of: intSetA) //true intSetB.isStrictSubset(of: intSetA) //false intSetC.isSubset(of: intSetA) // true intSetC.isStrictSubset(of: intSetA) //true |

The opposite principle is a superset:

1 2 3 4 |
let intSetA: Set = [1,2,3,4,5,6,7,8,9,0] let intSetC: Set = [3,4,5] intSetA.isSuperset(of: intSetC) //true intSetA.isStrictSuperset(of: intSetC) //true |

Two sets are disjoint, if they don’t have any element in common:

1 2 3 4 5 6 |
let intSetA: Set = [1,2,3,4,5,6,7,8,9,0] let intSetC: Set = [3,4,5] let intSetD: Set = [13,14,15] intSetA.isDisjoint(with: intSetC) //false intSetA.isDisjoint(with: intSetD) //true |

You can combine two sets to create a new one. A union of two sets contains all elements from both sets:

1 2 3 4 5 |
let stringSetA: Set = ["a","b","c"] let stringSetB: Set = ["c","d","e"] let unionSetAB = stringSetA.union(stringSetB) print(unionSetAB) //["d", "b", "c", "a", "e"] |

An intersection on the other hand contains only the elements, that are in both sets:

1 2 3 4 5 |
let stringSetA: Set = ["a","b","c"] let stringSetB: Set = ["c","d","e"] let intersectionAB = stringSetA.intersection(stringSetB) print(intersectionAB) //[“c”] |

Of course you can also store values of your own type in a set. This type could be for example a struct or a class. However, in order for the set to work properly, this type has to conform to the hashable protocol.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Movie: Hashable { var title: String var year: Int init(title: String, year: Int) { self.title = title self.year = year } static func == (lhs: Movie, rhs: Movie) -> Bool { return lhs.title == rhs.title && lhs.year == rhs.year } var hashValue: Int { return title.hashValue ^ year.hashValue } } let terminator = Movie(title: "Terminator", year: 1980) let backToTheFuture = Movie(title: "Back to the Future", year: 1985) let movieSetA: Set = [terminator,backToTheFuture] |

Title image: @ LaineN / shutterstock.com

Swift: Property wrappers

Swift: The differences between structs and classes

Swift: Reference Equality and Value Equality For Classes

Properties in Swift

Swift: Comparing Enums With Associated Values

Swift: Extensions

March 2017: The Current State Of Swift

Sorting Arrays in Swift