Stack implementation in Swift

10,345

Solution 1

Details

  • Swift 5.1, Xcode 11.3.1

Generic Stack Implementation

Stackable protocol

protocol Stackable {
    associatedtype Element
    func peek() -> Element?
    mutating func push(_ element: Element)
    @discardableResult mutating func pop() -> Element?
}

extension Stackable {
    var isEmpty: Bool { peek() == nil }
}

Stack

struct Stack<Element>: Stackable where Element: Equatable {
    private var storage = [Element]()
    func peek() -> Element? { storage.last }
    mutating func push(_ element: Element) { storage.append(element)  }
    mutating func pop() -> Element? { storage.popLast() }
}

extension Stack: Equatable {
    static func == (lhs: Stack<Element>, rhs: Stack<Element>) -> Bool { lhs.storage == rhs.storage }
}

extension Stack: CustomStringConvertible {
    var description: String { "\(storage)" }
}
    
extension Stack: ExpressibleByArrayLiteral {
    init(arrayLiteral elements: Self.Element...) { storage = elements }
}

Usage

var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.peek())
print(stack.pop())
print(stack)
print(stack == Stack<Int>())
stack = [3,2,1]
print(stack)

Solution 2

There's no problem with what you're doing there - that's just not the syntax for declaring an array. If you want an array of 5 stacks, you can do this:

[IntStack(), IntStack(), IntStack(), IntStack(), IntStack()]

Or, you can initialise the array like this:

Array(count: 5, repeatedValue: IntStack())

Also, you don't need to mark your functions as mutating unless they actually mutate the structure - so count() and show() don't need it.

Solution 3

It's possible to just extend arrays with stack specific methods. This might or might not be what you want, depending on if you want to disallow array like access.

protocol Stack {
    associatedtype Element
    
    mutating func push(item: Element)
    
    // allows discarding the result without generating a warning.
    @discardableResult
    mutating func pop() -> Element?
    
    func peek() -> Element?
    
    var count: Int { get }
}

extension Array: Stack {
    mutating func push(item: Element) {
        self.append(item)
    }
    
    mutating func pop() -> Element? {
        if let last = self.last {
            self.remove(at: self.count - 1)
            return last
        }
        
        return .none
    }
    
    func peek() -> Element? {
        self.last
    }
}

Simple test case:

class StackTests: XCTestCase {
    
    func testExample() throws {
        var stack = Array<Int>()
        
        XCTAssertEqual(stack.peek(), .none, "stack is empty, peek returns none")
        XCTAssertEqual(stack.pop(), .none, "stack is empty, pop returns none")

        stack.push(item: 0)
        stack.push(item: 1)
        stack.push(item: 2)
        
        XCTAssertEqual(stack.peek(), 2)
        XCTAssertEqual(stack.pop(), 2)
        
        XCTAssertEqual(stack.peek(), 1)
        XCTAssertEqual(stack.pop(), 1)
        
        XCTAssertEqual(stack.peek(), 0)
        XCTAssertEqual(stack.pop(), 0)
    }
}

Solution 4

There is no need to declare the size of the stack when you init it. Jus calling this should be enough.

var lines = IntStack()

Also note that your count() and show() methods should not be mutating since they don't modify the struct in any way.

Share:
10,345

Related videos on Youtube

Plinio Vilela
Author by

Plinio Vilela

Updated on October 18, 2022

Comments

  • Plinio Vilela
    Plinio Vilela over 1 year

    I'm new to Swift and iOS programming.

    I'm trying to test out a simple algorithm and need an array of Stacks. Don't have to be anything fancy (Stacks of Ints will do).

    I got the Stack implementation from The Swift Programming Language documentation:

    struct IntStack {
        var items = [Int]()
        mutating func push(item: Int) {
            items.append(item)
        }
        mutating func pop() -> Int {
            return items.removeLast()
        }
        mutating func count() -> Int {
            return items.count
        }
        mutating func show() {
            println(items)
        }
    }
    

    The count and show functions are my contribution. But when I try to declare an array of Stacks I get an error...

    var lines = IntStack()[5]
    

    "IntStack" does not have a member named subscript

    I'm guessing it has something to do with Optionals but can figure out what it is.

    Any help?

  • Martin R
    Martin R almost 9 years
    I don't think that you need Repeat here, Array(count: 5, repeatedValue: IntStack()) should work as well.
  • oisdk
    oisdk almost 9 years
    Ooh, didn't know about that. Thanks!
  • Plinio Vilela
    Plinio Vilela almost 9 years
    Thanks guys! I used: Array(count: 5, repeatedValue: IntStack()) and removed the mutating from count() and show() (never use CMD+C CMD+V while programming), and it worked! This Array instantiation syntax is very weird to me, but I guess I got the point. Thanks again!!
  • Caleb
    Caleb almost 5 years
    OP is trying to declare an array of stacks, not a single stack with a particular size.
  • Binarian
    Binarian almost 5 years
    And you are not showing any Stack implementation at all.
  • Kaolin Fire
    Kaolin Fire over 3 years
    @PlinioVilela this is ancient but seems like this should be the accepted answer?