How to use Sets in Swift

How to use Sets in Swift

Set are basically a collection of items that aren’t ordered but are unique. Let's go over different operations/functions that Swift has when it comes to Sets.

Creating a Set

Initialize an empty set

Sets in swift are of a generic nature so they can hold any type if it conforms to Hashable Protocol. For the simplicity of this article, we will use String and Int.

var fruits = Set<String>()

Initialize a Set with elements

We can also initialize a set with some default elements.

var fruits:Set<String> = ["apple","mango","guava"]

Initialize a Set with a capacity

We can set a space pre-allocated for minimum number/capacity

var fruits = Set<String>(minimumCapacity: 2)

Inspecting a set

Check for empty

Since Set conforms to Collection Protocol we can use a check for isEmpty.

var fruits = Set<String>()
fruits.isEmpty //true

Count

We can easily get the number of elements in our Set by accessing the count property.

var fruits:Set<String> = ["apple","mango","guava"]
fruits.count //3

Capacity

This property returns the number of elements set can contain without allocation any additional storage

var fruits:Set<String> = ["apple","mango","guava"]
fruits.capacity //3

Contains

This function is really useful when it comes to checking if a set contains an element or not. This function returns a bool.

var fruits:Set<String> = ["apple","mango","guava"]
fruits.contains("grape") // false
fruits.contains("apple") // true

Adding Elements

Insert

We can add an element to our Set in swift using the insert function. This will only insert if the elements don't exist already.

var fruits:Set<String> = ["apple","mango","guava"]
fruits.insert("grape")  //(inserted true, memberAfterInsert "grape")
print(fruits)  //["mango", "apple", "guava", "grape"]

If you pay attention to the output of the insert function, we get a tuple back which gives us info regarding whether the element was inserted or not. This value from the tuple is very useful to check if the insertion actually happened.

ReserveCapacity

This reserves enough space to hold the number of elements we want.

var fruits = Set<String>()
fruits.reserveCapacity(5)

Removing Elements

Filter

Since Sets conforms to Collection protocol, we use advanced operations like filters very easily.

var numbers:Set<Int> = [1,2,3,4,5,6,7,8,9,10]
let evenNUmbers = numbers.filter {
return $0%2 == 0
}
evenNUmbers //{6, 10, 4, 2, 8}

Remove

This function removes the element that is passed from the Set

var fruits:Set<String> = ["apple","mango","guava"] //{"apple", "mango", "guava"}
fruits.remove("apple")
fruits //{"mango", "guava"}

RemoveFirst

This removes the first element from the unordered set. Always remember it can remove any element as it in an unordered list.

var fruits:Set<String> = ["apple","mango","guava"] //{"apple", "mango", "guava"}
fruits.removeFirst()
fruits //{"mango", "guava"}

RemoveAll

This clears the Set.

var fruits:Set<String> = ["apple","mango","guava"] //{"apple", "mango", "guava"}
fruits.removeAll() //Set([])

Combining Sets

Union

This helps us combine results from two sets. Here we take two sets, one set with even number and one with odd numbers.

let evenNumber:Set<Int> = [2,4,6,8] //{2, 4, 8, 6}
let oddNumbers:Set<Int> = [1,3,5,7] // {7, 3, 1, 5}
let result = evenNumber.union(oddNumbers) //{4, 7, 3, 1, 6, 2, 5, 8}

If you see the code above the result set contains elements from both sets

Intersection

This helps us get the common part from both sets and return set with that. Let's look at the example below.

let numbers:Set<Int> = [1,2,3,4,5,6,7,8] //{2, 4, 8, 6}
let oddNumbers:Set<Int> = [1,3,5,7] // {7, 3, 1, 5}
let result = numbers.intersection(oddNumbers)//{5, 1, 7, 3}

Symmetric Difference

This function is exactly the opposite of Intersection and results in a Set that removes the common elements and returns everything else. Let's take an example

let letters:Set<Character> = ["a","b","c","d"] //{"d", "a", "b", "c"}
let vowels:Set<Character> = ["a","e","i","o","u"] // {"u", "a", "o", "e", "i"}
let result = letters.symmetricDifference(vowels)//{"u", "d", "c", "b", "i", "e", "o"}

In the example above, character a is common in letters and vowels set so the result set contains everything from both sets except the common part a .

Subtract

This function helps in removing the elements from a given set. Let’s take an example

var numbers:Set<Int> = [1,2,3,4,5,6,7,8,9,10] //{1, 4, 6, 3, 7, 10, 5, 2, 8, 9}
let evenNumbers:Set<Int> = [2,4,6,8] //{4, 2, 6, 8}
numbers.subtract(evenNumbers) //{1, 3, 7, 10, 5, 9}

If you look at the example above, after subtracting evenNumbers set from numbersSet we got a set which now has only even numbers.

Finding Elements

Min

This gives you a minimum element of the set.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
numbers.min() //1

Max

This gives you the maximum of the set.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
numbers.max() //4

First(where:)

This helps you find the element in the set that satisfy a condition in the where clause. Please note, since the set is an unordered collection you will get different results running the same code below as it just returns the first one it matches the required condition.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
let result = numbers.first { $0%2 == 0}//4
print(result) //4

Transforming a Set

Map

As sets implement the collection protocol we can use advanced function like map. Map basically transforms every element of the collection the way we want and gives us a list. Let's say we have a set of numbers 1,2,3,4. Our map will multiple each one of them by 2.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
let result = numbers.map{$0 * 2}
print(result) // [2,4,6,8]

Reduce

Reduce can be used to combine the result of the collection. In our example, we will add the elements of our Set.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
let result = numbers.reduce(0) {$0 + $1}
print(result) // 10

Iterating Over a Set

ForEach

This will help us calling the same closure/transformation on each element in our Set. In the example below, we are just printing each and every element of the Set.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
numbers.forEach {
print($0)
}

Enumerated

This is another way we can iterate over Set’s element. In this case, we will access to index too along with the element itself.

var numbers:Set<Int> = [1,2,3,4] //{2, 3, 4, 1}
for (index,element) in numbers.enumerated() {
print("index is \(index) and element is \(element)")
}

Here is the output.

index is 0 and element is 2
index is 1 and element is 3
index is 2 and element is 4
index is 3 and element is 1

Conclusion

Sets hold unordered collection but their ability to hold unique value makes them a very useful data structure in our day to day implementation. I hope after reading this article you are all set to use Sets.

References

developer.apple.com/documentation/swift/set