In this tutorial, we’ll be discussing and implementing the Data Structure: Stacks, using Swift. We’ll see how Swift Generics make it easy to create Generic Stacks.
Swift Stack
Stacks are a data structure that is used to hold the data in a particular order.
Let’s see how they are ordered:
The order is like a pile of books. You can keep inserting a new book in the collection at the top.
You can only remove or view the topmost book. That means to remove the bottom-most book, you’ll have to remove all the books above.
This order is known as Last in First Out(LIFO).
Following diagram showcases an example:
- Push is used to insert an element to a stack.
- Pop is used to remove the topmost element.
- Peek is used to view the topmost element.
By default, if the Stack is empty, it returns a nil.
We can create Stacks using Arrays, LinkedList etc. We’ll use Arrays for this tutorial.
Important Use case for Stacks
In a music playlist application, where songs are queued and set on shuffle, often you realize that going back and forth changes the next song to a new random song.
This happens through Stacks. The latest song is added on top of a stack. If you don’t like that song, you can always press back (pop) and forward(push) to insert a new random song in the queue.
Let’s launch the XCode playground and implement Swift Stacks.
Create a Stack
We can create a Stack in Swift in the following way:
struct Stack {
private var myArray: [String] = []
}
We’ve defined a structure Stack that would contain Array of Strings.
Let’s define the functions push, pop and peek in the Swift Structure.
Push
mutating func push(_ element: String) {
myArray.append(element)
}
This push function appends the new element to the LAST of the array.
Pop
mutating func pop() -> String? {
return myArray.popLast()
}
This pop function removes the LAST element using the popLast()
function available with Swift Arrays.
We’ve used an Optional return type String since it can return a nil.
Peek
func peek() -> String {
guard let topElement = myArray.last else { print("This stack is empty.") }
return topElement
}
If you want to show a custom error message, instead of using Optionals, use the guard let
statement of Swift.
This is how our final structure looks in the XCode Playground.
struct Stack {
private var myArray: [String] = []
mutating func push(_ element: String) {
myArray.append(element)
}
mutating func pop() -> String? {
return myArray.popLast()
}
func peek() -> String {
guard let topElement = myArray.last else {return "This stack is empty."}
return topElement
}
}
var stack = Stack()
stack.peek()
stack.push("Swift Arrays")
stack.push("Swift LinkedList")
stack.push("Swift Stack")
print(stack)
stack.peek()
stack.pop()
stack.pop()
stack.pop()
stack.peek()
stack.pop()
print stack prints the array
The result of the above Stack operations is:
The above Stack can only hold Strings. Besides, it doesn’t print the stack contents beautifully.
For that, we can use the CustomStringConvertible
protocol as an Extension on our Structure.
Let’s create an extension for the Stack structure below:
extension Stack: CustomStringConvertible {
var description: String {
let header = "****Swift Stack Begin****n"
let bottomDivider = "n****Swift Stack End*****n"
let elements = myArray.joined(separator: "n")
return header + elements + bottomDivider
}
}
Following is the output from stack.description
It’s printing the stack in the order in which it was pushed. We need to reverse it using the reversed() method:
let elements = myArray.reversed().joined(separator: "n")
The correct stack order is now:
Swift Generic Stacks
Let’s make the above Swift stack generic.
You just need to update your Stack definition with a generic parameter in brackets!
struct Stack<T> {
private var myArray: [T] = []
mutating func push(_ element: T) {
myArray.append(element)
}
mutating func pop() -> T? {
return myArray.popLast()
}
func peek() -> T? {
return myArray.last
}
}
Note: In the CustomStringConvertible protocol, we were joining the elements using joined
.
This won’t work for non-string elements. So we need to first map the element to a string using the map operator and then join.
let elements = myArray.reversed().map{ "($0)" }.joined(separator: "n")
$0 refers to the current element that’s being mapped.
We’ve used a Stack of type Any. You can pass anything in place.
This brings an end to this tutorial on Swift Stack implementation.