Published by Arunprasadh C on 06 May 2022 • Last Updated on 19 May 2022
Collections in Swift
As in other languages, Collections in Swift are used to store collections of values. There are three primary kinds of Collections available in Swift :
Arrays
An array is an ordered collection of data. Unlike C/C++, Swift allows both homogeneous and heterogeneous arrays. Arrays in Swift are handled by the Array<DataType>
struct
. Arrays can be declared either by type annotating as Array<DataType>
or simply as Array
or [DataType]
or by specifying the array values as comma separated literals within [ ]
or using Array constructor. Immutable arrays can be declared using let
keyword while mutable ones can be declared using var
keyword.
Syntax :
var arrayName: [DataType] = [Value1, Value2, Value3, ....]
or
var arrayName: Array<DataType> = [Value1, Value2, Value3, ....]
or
var arrayName: Array = [Value1, Value2, Value3, ....]
or
var arrayName = [DataType]() // Empty array
or
var arrayName = Array<DataTyoe>(repeating: Int, count: Int) // generates an array with repeating elements of given count
Note that [DataType]()
and Array<DataType>()
are equivalent.
Example 1:
var odd : Array = [1,3,5]
var even : [Int] = [2,4,6]
for i in 0...2
{
print(odd[i], even[i], separator: ", ", terminator: ", ")
}
Output 1:
1, 2, 3, 4, 5, 6,
Example 2:
var hellos = Array(repeating: "hello", count: 5)
print(hellos)
Output 2:
["hello", "hello", "hello", "hello", "hello"]
Heterogeneous Arrays can be declared by using Any
type, which can literally represent any type of value.
Example 3:
var anyArray: [Any] = [1, "Hello", 4.5, true]
print(anyArray)
for x in anyArray
{
print(type(of: x), separator: ", ", terminator: ", ")
}
Output 3:
[1, "Hello", 4.5, true]
Int, String, Double, Bool,
Even an array of tuples can be declared and used as shown below. The subscript syntax []
is used to access and modify array elements.
Example 4:
typealias Rectangle = (length: Int, breadth: Int)
let rect1 = Rectangle(length: 4, breadth: 3)
let rect2 = Rectangle(length: 8, breadth: 7)
let rect3 = Rectangle(length: 10, breadth: 4)
let rectangles: [Rectangle] = [rect1, rect2, rect3]
for i in rectangles.indices
{
print("The area of rectangle with length: \(rectangles[i].length) and breadth: \(rectangles[i].breadth) is: \(rectangles[i].length * rectangles[i].breadth)")
}
Output 4:
The area of rectangle with length: 4 and breadth: 3 is: 12
The area of rectangle with length: 8 and breadth: 7 is: 56
The area of rectangle with length: 10 and breadth: 4 is: 40
Many useful in-built functions are available for Arrays in Swift. The following example showcases some of them:
Example 5:
var intArray = [1, 3, 4, 5, 7, 8, 9]
print("Original array: \(intArray)")
intArray.insert(2, at: 1) // Insert element at given index
intArray.insert(6, at: 5) // Insert element at given index
print("Array after inserting elements: \(intArray)")
intArray.append(10) // Append element at last index
print("Array after appending element at last: \(intArray)")
print("Number of elements in array: \(intArray.count)")
intArray.shuffle() // Randomly shuffle the elements of array
print("Array after shuffling elements: \(intArray)")
intArray.swapAt(2, 4)
print("Array after swapping indices 2 and 4: \(intArray)")
print("Random element from array: \(intArray.randomElement()!)") // Get a random element from array
intArray.sort{ $0 > $1 }
print("Sorting array in descending order: \(intArray)")
intArray.reverse()
print("Getting Original array by reversing the array: \(intArray)")
var evenArray = intArray.filter{ $0.isMultiple(of: 2) } // Filter the elements of array based on a given predicate
print("Filtered array with only even elements: \(evenArray)")
evenArray.removeLast() // Remove the last element of array
print("Even array after removing last element: \(evenArray)")
print("Does even array contain element 4 ? \(evenArray.contains(4))")
evenArray.removeAll() // Remove all elements from Even Array
print("Is Even Array empty ? \(evenArray.isEmpty)") // Check if even array is empty
Output 5:
Original array: [1, 3, 4, 5, 7, 8, 9]
Array after inserting elements: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Array after appending element at last: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Number of elements in array: 10
Array after shuffling elements: [10, 1, 3, 9, 4, 5, 8, 6, 7, 2]
Array after swapping indices 2 and 4: [10, 1, 4, 9, 3, 5, 8, 6, 7, 2]
Random element from array: 8
Sorting array in descending order: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Getting Original array by reversing the array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Filtered array with only even elements: [2, 4, 6, 8, 10]
Even array after removing last element: [2, 4, 6, 8]
Does even array contain element 4 ? true
Is Even Array empty ? true
2D Arrays can be created by optionally type annotating as [[DataType]]
or Array<[DataType]>
or Array<Array<DataType>>
or [Array<DataType>]
or simply as Array
and assigning them to literals nested array literals.
Example 6:
var twoDAry : Array<[Int]> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(twoDAry)
print(type(of: twoDAry))
print("Iterating using for-in loop")
for x in twoDAry
{
for y in x
{
print(y, terminator: ", ")
}
}
print("\nIterating using while loop")
var i: Int = twoDAry.startIndex
while(i < twoDAry.endIndex)
{
var j: Int = twoDAry[i].startIndex
while(j < twoDAry[i].endIndex)
{
print(twoDAry[i][j], terminator: ", ")
j += 1
}
i += 1
}
Output 6:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Array<Array<Int>>
Iterating using for-in loop
1, 2, 3, 4, 5, 6, 7, 8, 9,
Iterating using while loop
1, 2, 3, 4, 5, 6, 7, 8, 9,
Sets
A set is an unordered collection of unique values. The elements of a Set cannot be duplicate. Swift Set
is similar to unordered_set
of C++ and HashSet
of Java. A var
or let
specifying a Set
value must always provide type annotation as either Set
or Set<DataType>
because for a Set
too, array literals (comma separated values within []
) are used for specifying values.
Syntax :
var setName: Set = [value1, value2, value3....]
or
var setName: Set<DataType> = [value1, value2, value3....]
Example 1:
var intSet: Set = [1, 2, 3, 4]
print(type(of: intSet))
print(intSet)
Output 1:
Set<Int>
[3, 4, 1, 2] //Since it is an unordered collection, insertion order is not maintained.
Example 2:
var uniqueSet: Set<Int> = Set<Int>() // Empty Set
for i in 1...10
{
uniqueSet.insert(i)
}
print(uniqueSet)
for i in 5...15
{
uniqueSet.insert(i)
}
print(uniqueSet)
Output 2:
[7, 6, 8, 9, 5, 1, 4, 2, 10, 3]
[14, 9, 3, 8, 10, 15, 5, 4, 13, 1, 2, 6, 11, 7, 12] // Since a Set allows only unique values, values from 5 to 10 are not inserted again.
The elements of a Set
can be iterated using for
-in
loop. Set
also provides Set.Index
instead of Int
index for accessing elements. But, in practical use, the Set.Index
is not used as the elements are unordered and each time the Index may return a different element.
Example 3:
var charSet: Set<Character> = ["A", "B", "C", "D", "E", "F"]
for c in charSet
{
print(c, terminator: " -> ")
}
print()
for c in charSet.sorted(by: >)
{
print(c, terminator: " -> ")
}
Output 3:
D -> A -> F -> B -> C -> E ->
F -> E -> D -> C -> B -> A ->
The insert()
function is used to insert an element into the Set
. The insert()
function returns a Tuple
containing two members: a Bool
value named inserted
representing whether the element was inserted (will be true
if the element is not already there in the set and hence was inserted) and a DataType
value named memberAfterInsert
representing the inserted element.
Example 4:
var intSet: Set = [1, 2, 3, 4, 5, 6]
print("Original Set: \(intSet)")
let result = intSet.insert(10)
if(result.inserted == true)
{
print("\(result.memberAfterInsert) was inserted successfully into the set !")
print("Modified Set: \(intSet)")
}
Output 4:
Original Set: [6, 4, 2, 1, 5, 3]
10 was inserted successfully into the set !
Modified Set: [5, 1, 6, 10, 2, 4, 3]
Heterogeneous Set
can be declared using AnyHashable
type since Set
allows only elements conforming to Hashable
Protocol.
Example 5:
var anySet: Set<AnyHashable> = [1, "Hello", true, "World", 6.5]
anySet.insert(8.9)
anySet.forEach { element in
print(element)
}
Output 5:
1
Hello
true
6.5
World
8.9
The following example showcases various methods available in Set
:
Example 6:
var evenSet: Set = [2, 4, 6, 8, 10, 12]
print("Original Set: \(evenSet)")
evenSet.insert(4)
evenSet.insert(13) // Insert element into Set if it doesn't exist
evenSet.insert(20)
evenSet.insert(21)
print("Set after inserting elements: \(evenSet)")
evenSet.remove(21) // Remove given element from Set if it exists
evenSet.remove(13)
print("Set after removing elements: \(evenSet)")
print("Does set have element 8 ? \(evenSet.contains(8))")// Returns true if given element is present
print("Sorted View of Set: \(evenSet.sorted())") // Returns a sorted array using elements of set
print("Random element of Set: \(evenSet.randomElement()!)") //Random element from Set
evenSet.removeAll() // Remove all elements from Set
print("Length of Set after removing elements: \(evenSet.count)")
Output 6:
Original Set: [2, 12, 4, 6, 8, 10]
Set after inserting elements: [4, 10, 6, 20, 8, 2, 12, 13, 21]
Set after removing elements: [4, 10, 6, 20, 8, 2, 12]
Does set have element 8 ? true
Sorted View of Set: [2, 4, 6, 8, 10, 12, 20]
Random element of Set: 4
Length of Set after removing elements: 0
Mathematical Set Operations
Swift Set
provides different built-in methods to perform Mathematical Set Operations like Union, Intersection, Subtraction, and Symmetric Difference.
Union Operation
The Union of two Sets A and B includes all the elements of set A and B (A ⋃ B). We use the union()
method to perform the Set Union Operation.
Example 7:
let even: Set = [0, 2, 4, 6, 8]
let odd: Set = [1, 3, 5, 7, 9]
print("Even set: \(even)")
print("Odd set: \(odd)")
let union = even.union(odd)
print("Sorted view of Union of even and odd: \(union.sorted())")
Output 7:
Even set: [0, 4, 8, 6, 2]
Odd set: [7, 3, 5, 9, 1]
Sorted view of Union of even and odd: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Intersection Operation
The Intersection of two Sets A and B includes all the elements common to both set A and B (A ⋂ B). We use the intersection()
method to perform the Set Intersection Operation.
Example 8:
let set1: Set = [1, 2, 3, 4, 5]
let set2: Set = [0, 2, 4, 6, 8]
print("Set 1: \(set1)")
print("Set 2: \(set2)")
let intersection = set1.intersection(set2)
print("Intersection of Set 1 and Set 2: \(intersection)")
Output 8:
Set 1: [1, 2, 4, 3, 5]
Set 2: [6, 8, 4, 0, 2]
Intersection of Set 1 and Set 2: [2, 4]
Set Difference/Subtraction Operation
The Subtraction of two Sets A and B includes all the elements present in A but not in B (A - B). We use the subtracting()
method to perform the Set Subtraction Operation.
Example 9:
let set1: Set<AnyHashable> = [1, 2.5, "Hello", true]
let set2: Set<AnyHashable> = [2.5, true, false, 6, 8]
print("Set 1: \(set1)")
print("Set 2: \(set2)")
let subtraction = set1.subtracting(set2)
print("Subtraction of Set 1 and Set 2: \(subtraction)")
Output 9:
Set 1: [AnyHashable(2.5), AnyHashable("Hello"), AnyHashable(true), AnyHashable(1)]
Set 2: [AnyHashable(6), AnyHashable(2.5), AnyHashable(8), AnyHashable(true), AnyHashable(false)]
Subtraction of Set 1 and Set 2: [AnyHashable("Hello"), AnyHashable(1)]
Symmetric Difference Operation
The Symmetric Difference between two Sets A and B includes all elements of A and B without the common elements ((A - B) ⋃ (B - A)). We use the symmetricDifference()
method to perform the Set Symmetric Difference Operation.
Example 10:
let set1: Set = [1, 2, 3, 5]
let set2: Set = [1, 8, 9, 5]
print("Set 1: \(set1)")
print("Set 2: \(set2)")
let subtraction1 = set1.subtracting(set2)
let subtraction2 = set2.subtracting(set1)
let sub1Usub2 = subtraction1.union(subtraction2)
let symmetricDifference = set1.symmetricDifference(set2)
print("Symmetric Difference of two sets: \(symmetricDifference)")
print("Are Symmetric Difference and Union of A - B and B - A the same ? \(sub1Usub2 == symmetricDifference)")
Output 10:
Set 1: [5, 2, 3, 1]
Set 2: [9, 1, 5, 8]
Symmetric Difference of two sets: [2, 3, 9, 8]
Are Symmetric Difference and Union of A - B and B - A the same ? true
How to check if a Set is a Subset of another Set
The isSubset(of: )
method is used to check if Set
is a subset of another Set
.
Example 11:
let set1: Set = [1, 2, 3, 4, 5, 6, 7, 8]
let set2: Set = [2, 4, 6, 8]
print("Set 1: \(set1)")
print("Set 2: \(set2)")
print("Is Set 2 a subset of Set 1 ? \(set2.isSubset(of: set1))")
Output 11:
Set 1: [3, 2, 5, 7, 6, 1, 8, 4]
Set 2: [4, 8, 2, 6]
Is Set 2 a subset of Set 1 ? true
Dictionaries
Swift Dictionary
is an Unordered Collection of Items. It stores elements in key/value pairs. Here, keys are unique identifiers that are associated with each value. The Key has to be unique and must conform to the Hashable
Protocol. Swift Dictionary
is similar to unordered_map
of C++ and HashMap
of Java. A Dictionary can be declared either by specifying Dictionary Literal ([HashableType : Type]
), or by annotating the variable/constant as Dictionary
along with specification of the Literal, or by annotating the variable/constant as Dictionary<DataType, DataType>
, or by annotating as [HashableType : Type]
.
Syntax :
var dictName = [key1 : value1, key2 : value2, key3 : value3,....]
or
var dictName: Dictionary = [key1 : value1, key2 : value2, key3 : value3,....]
or
var dictName: Dictionary<HashableType, Type> = [key1 : value1, key2 : value2, key3 : value3,....]
or
var dictName: [HashableType : Type] = [key1 : value1, key2 : value2, key3 : value3,....]
Example 1:
//Creating empty Dictionary
var empty1: [Int : Float] = [Int : Float]()
var empty2: [String : Int] = [:]
var empty3 = Dictionary<Double, Int>()
print(empty1, empty2, empty3, separator: ", ")
print(type(of: empty1), type(of: empty2), type(of: empty3), separator: ", ")
Output 1:
[:], [:], [:]
Dictionary<Int, Float>, Dictionary<String, Int>, Dictionary<Double, Int>
The values can be accessed in O(1) lookup time using keys, as the unique keys are hashed internally. The values of a Dictionary
can be accessed via the subscript syntax []
which takes key as the argument. Note that a Dictionary
always returns the value wrapped inside an Optional
type as the any given may/may not exist in the Dictionary
. Even if the value is annotated as an Optional
type, assigning nil
to a value pointed by a key will remove that key-value pair from the Dictionary
. If you’re doubtful about the existence of a key-value pair in a Dictionary
, you can give a default value in the subscript syntax [_ key, default: defaultValue]
which will be used when the given key is not present in the Dictionary
.
Example 2:
var dict = [1 : "One", 2 : "Two", 3 : "Three", 4 : "Four"]
print(dict)
print(type(of: dict))
dict[3] = nil //Remove 3 : "Three" from dict
print(dict)
print("4 in words is: \(dict[4]!)")
print(dict[5,default:"Word Representation not present"])
Output 2:
[1: "One", 2: "Two", 3: "Three", 4: "Four"]
Dictionary<Int, String>
[1: "One", 2: "Two", 4: "Four"]
4 in words is: Four
Word Representation not present
The following example showcases various operations on a Dictionary
:
Example 3:
let even = "EVEN", odd = "ODD"
var evenOdd : [Int : String] = [2 : even, 3 : even, 9 : odd, 10 : even]
print("Original Dictionary: \(evenOdd)")
evenOdd[3] = odd // Modifying value of key
print("Modified Dictionary: \(evenOdd)")
evenOdd[19] = even // Adding new key-value pair
evenOdd[22] = odd // Adding new key-value pair
print("Modified Dictionary: \(evenOdd)")
evenOdd[19] = nil // Removing key-value pair from Dictionary
evenOdd.removeValue(forKey: 22) // Removing key-value pair from Dictionary
print("Modified Dictionary: \(evenOdd)")
print("Keys of Dictionary in sorted order: \(evenOdd.keys.sorted())") //Access all keys
print("Values of Dictionary: \(evenOdd.values)") // Access all values
print("Key-Value pairs sorted in descending order of Keys: \(evenOdd.sorted(by: >))") // Access all pairs in descending order of keys
print("Shuffled Dictionary: \(evenOdd.shuffled())") // Shuffle key-value pairs of dictionary
let is11Present = evenOdd.contains { k,v in //Checking presence of key:value pair using contains method
return k==11 && v==odd
}
print("Is 11 : \"ODD\" present in Dictionary ? \(is11Present)")
print("Number of elements in Dictionary: \(evenOdd.count)")
Output 3:
Original Dictionary: [3: "EVEN", 9: "ODD", 2: "EVEN", 10: "EVEN"]
Modified Dictionary: [3: "ODD", 9: "ODD", 2: "EVEN", 10: "EVEN"]
Modified Dictionary: [3: "ODD", 9: "ODD", 19: "EVEN", 22: "ODD", 2: "EVEN", 10: "EVEN"]
Modified Dictionary: [3: "ODD", 9: "ODD", 2: "EVEN", 10: "EVEN"]
Keys of Dictionary in sorted order: [2, 3, 9, 10]
Values of Dictionary: ["ODD", "ODD", "EVEN", "EVEN"]
Key-Value pairs sorted in descending order of Keys: [(key: 10, value: "EVEN"), (key: 9, value: "ODD"), (key: 3, value: "ODD"), (key: 2, value: "EVEN")]
Shuffled Dictionary: [(key: 3, value: "ODD"), (key: 9, value: "ODD"), (key: 10, value: "EVEN"), (key: 2, value: "EVEN")]
Is 11 : "ODD" present in Dictionary ? false
Number of elements in Dictionary: 4
Heterogeneous Dictionaries can be declared using AnyHashable
as Key since the Key of a Dictionary
should conform to the Hashable
Protocol and using Any
as Value.
Example 4:
var anyDict: [AnyHashable : Any] = ["Dummy" : 1, 1.5 : 4, 9.8 : true, false : "Hello"]
print(anyDict)
print(type(of: anyDict))
for x in anyDict.keys
{
print("\(x) : \(anyDict[x]!)")
}
Output 4:
[AnyHashable("Dummy"): 1, AnyHashable(false): "Hello", AnyHashable(1.5): 4, AnyHashable(9.8): true]
Dictionary<AnyHashable, Any>
Dummy : 1
false : Hello
1.5 : 4
9.8 : true
The zip(_:,_:)
Function
Swift provides the zip(_:,_:)
Function to associate one sequence with another (Just like Python zip()
Function and Java Stream’s mapToObj()
Method). The first sequence given in parameter is taken as the Key Sequence and the second one is taken as the Value Sequence. The zip(_:,_:)
returns a Zip2Sequence
object which can be passed to the Dictionary
initializer to get a zipped Dictionary
object.
Example 5:
let nums = [1, 2, 3, 4, 5]
let textualNums = ["One", "Two", "Three", "Four", "Five"]
let dict = Dictionary(uniqueKeysWithValues: zip(nums, textualNums))
print("Zipped Dictionary: \(dict)")
print(type(of: dict))
Output 5:
Zipped Dictionary: [2: "Two", 5: "Five", 3: "Three", 1: "One", 4: "Four"]
Dictionary<Int, String>
When the two sequences are of unequal lengths, the tailing elements are ignored by the zip(:_,:_)
function.
Now that we have learnt about Collections in Swift, we can move on to learn about Functions and Closures in Swift.