简体   繁体   中英

Stack implementation in Swift

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?

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)

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.

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)
    }
}

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.

Just look into this code. Stack example with generic data type and without using the array.

class Node<T>: CustomStringConvertible {

let value: T
var next: Node?

var description: String {
    guard let next = next else { return "\(value)" }
    return "\(value)\n" + String(describing: next)
}

init(value: T) {
    self.value = value
}
}


// Stack  class to hold all items
class Stack<T>: CustomStringConvertible {

var top: Node<T>?

var description: String {
    guard let top = top else { return "---- Stack is EMPTY ----" }
    return "---- Stack Begin ----\n" + String(describing: top) + "\n---- Stack End ----"
}

// push
func push(_ value: T) {
    let currentTop = top
    top = Node(value: value)
    top?.next = currentTop
}

@discardableResult
func pop() -> T? {
    let currentTop = top
    top = top?.next
    return currentTop?.value
}

@discardableResult
func peek() -> T? {
    return top?.value
}
}

Excellent implementation! One thought: I think it should be:

func peek() -> Element? { storage.last }

Here is a Stack implementation using Swift Generics,

struct Fruit {
let fruitName : String
let color : String
init(_ name: String,_ color: String) {
    self.fruitName = name
    self.color = color
}
}

let fruit1 = Fruit("Apple", "Red")
let fruit2 = Fruit("Grapes", "Green")

let fruitStack = Stack<Fruit>()
fruitStack.push(fruit1)
fruitStack.push(fruit2)

let fruitFfromStack = fruitStack.pop()
print("Fruit popped from Stack, Name : \(String(describing: fruitFfromStack?.fruitName)) ,Color : \(String(describing: fruitFfromStack?.color))")
let fruitFfromStack1 = fruitStack.pop()
print("Fruit popped from Stack, Name : \(String(describing: fruitFfromStack1?.fruitName)) ,Color : \(String(describing: fruitFfromStack1?.color))")

Full code is here :

https://reactcodes.blogspot.com/2019/01/generic-stack-implementation-with.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM