Search code examples
swiftgenericsswift-array

Array / Stack contains function


I would like to give my STACK struct the function contains(element: Element) that returns a bool as to whether var contents contains the element provided.

struct Stack<T>: SequenceType, Equatable, Printable, DebugPrintable {
     typealias Element = T
     private var contents: [Element]
     var top: Int

     init(arrayLiteral elements: T...) {
          self.init(elements) }

     // easier initialization
     init<S: SequenceType where S.Generator.Element == Element>(_ sequence: S) {
          self.contents = [Element]()
          Swift.map(sequence) {self.contents[$0] = true }
     }

     // returns TRUE if the Stack contains <T> 'element'
     func contains(element: Element) -> Bool {
         return contents.filter(element != nil) ?? false
     }

I would like to be able to define a new STACK and search its contents like so:

 var newStack: Stack = [5, 23, 45, 100]
 newStack.contains(45)                      // returns TRUE

Currently the compiler gives an error of:

"Cannot invoke '??' with an argument list of type '(Array, BooleanLiteralConvertible)' "


Solution

  • First of all, the generic element type T must conform to Equatable so that you can compare the given element with the array elements using ==:

    struct Stack<T : Equatable> : YourProtocols... {
    

    The filter methods takes a closure which tests each array element:

    let filtered = contents.filter({ $0 == element})
    

    and returns a new array containing only the elements for which the test (the "predicate") yields true. But you don't need a new array, you want to test only for membership, and that can be done with the Swift contains() function:

    func contains(element: Element) -> Bool {
        return Swift.contains(contents, element)
    }
    

    Btw, your init method does not compile. It seems to be copied from a different collection type where the elements are stored in a dictionary. Here you can simply use that an array can be initialized with a sequence:

    init<S: SequenceType where S.Generator.Element == Element>(_ sequence: S) {
        self.contents = Array(sequence)
    }