Swift for-in loop with enumerate on custom Array2D class?

How would I go about implementing a custom enumerate function that makes something like this work (Swift 2):

for ((column, row), item) in Array2D.enumerate() { ... }

In my simple Array2D struct:

  • Why Swift is 100 times slower than C in this image processing test?
  • Passing array through segue in swift
  • Write array of floats to a wav audio file in swift
  • WKWebView didn't finish loading, when didFinishNavigation is called - Bug in WKWebView?
  • Multi-touch gesture in Sprite Kit
  • WKWebView: Is it possible to preload multiple URLs?
  • struct Array2D<T> : SequenceType {
        let columns: Int
        let rows: Int
        private var array: Array<T?>
    
        init(columns: Int, rows: Int) {
            self.columns = columns
            self.rows = rows
            array = Array(count: rows*columns, repeatedValue: nil)
        }
    
        subscript(column: Int, row: Int) -> T? {
            get {
                return array[columns*row + column]
            }
            set {
                array[columns*row + column] = newValue
            }
        }
    
        func generate() -> AnyGenerator<T?> {
            var column = 0
            var row = 0
    
            return anyGenerator() {
                guard row < self.rows else {
                    return nil
                }
    
                let item = self[column, row]
    
                if ++column == self.columns {
                    column = 0
                    ++row
                }
    
                return item
            }
        }
    }
    

    I couldn’t find any good explanation on implementing an enumerate function in Swift

    2 Solutions Collect From Internet About “Swift for-in loop with enumerate on custom Array2D class?”

    It might suffice defining your own enumerate taking advantage of the one you already have:

    func enumerate() -> AnyGenerator<((Int, Int), T?)> {
        var index = 0
        var g = array.generate()
        return anyGenerator() {
            if let item = g.next() {
                let column = index % self.columns
                let row = index / self.columns
                ++index
                return ((column, row) , item)
            }
            return nil
        }
    }
    

    Notice in this case you could avoid conforming to SequenceType since I use generate from the private array. Anyway it could be consistent to do so.

    Here is how then you could use it:

    var a2d = Array2D<Int>(columns: 2, rows: 4)
    a2d[0,1] = 4
    
    for ((column, row), item) in a2d.enumerate() {
        print ("[\(column) : \(row)] = \(item)")
    }
    

    Hope this helps

    The enumerate() function in Swift returns integers starting from 0 for the first part of its tuple. Those have nothing to do with the sequence you’re enumerating over. So, for instance, this won’t work:

    let word = "hello".characters
    
    for (index, letter) in word.enumerate() {
      print(word[index])
    }
    

    Because the indices of a characterView are String.Indexs.

    So there are several ways to get what you’re going for. The first is to just overload enumerate() for your struct. Again, there are a few days you could do this. First off, how about a function that uses your own generator, and uses its own logic to figure out the coordinates. This could work:

    func enumerate() -> AnyGenerator<((Int, Int), T?)> {
      let g = self.generate()
      var coord = -1
      return anyGenerator {
        g.next().map { ((++coord % self.columns, coord / self.columns), $0) }
      }
    }
    

    But you’re duplicating code there, especially from your generate method. Seeing you’re already using coordinates to return each element, why not just have your enumerate method be the default, and your generate method call on that. Something like this:

    // Original generate method, now returns the coords it used
    func enumerate() -> AnyGenerator<((Int, Int), T?)> {
      var column = 0
      var row = 0
    
      return anyGenerator() {
        guard row < self.rows else {
          return nil
        }
    
        let item = self[column, row]
    
        if ++column == self.columns {
          column = 0
          ++row
        }
    
        return ((column, row), item)
      }
    }
    
    // uses enumerate, ignores coords
    
    func generate() -> AnyGenerator<T?> {
      let g = self.enumerate()
      return anyGenerator {
        g.next().map { $1 }
      }
    }
    

    If you wanted to go a little overboard, you could write an enumerate function that enumerates the specific indices of its base. Call it specEnumerate:

    public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
    
      private var eG: Base.Generator
      private let sI: Base.Index
      private var i : Base.Index?
    
      public mutating func next() -> (Base.Index, Base.Generator.Element)? {
        i?._successorInPlace() ?? {self.i = self.sI}()
        return eG.next().map { (i!, $0) }
      }
    
      private init(g: Base.Generator, i: Base.Index) {
        self.eG = g
        self.sI = i
        self.i = nil
      }
    }
    
    public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
    
      private let col: Base
      public func generate() -> SpecEnumerateGen<Base> {
        return SpecEnumerateGen(g: col.generate(), i: col.startIndex)
      }
    }
    
    public extension CollectionType {
      func specEnumerate() -> SpecEnumerateSeq<Self> {
        return SpecEnumerateSeq(col: self)
      }
    }
    

    With this function, this would work:

    let word = "hello".characters
    
    for (index, letter) in word.specEnumerate() {
      print(word[index])
    }
    

    But your matrix struct is still a SequenceType, with no specific indices. For that, you’ll have to implement your own MatrixIndex:

    public struct MatrixIndex: BidirectionalIndexType {
    
      public let x, y : Int
    
      private let columns: Int
    
      public func successor() -> MatrixIndex {
        return (x + 1 == columns) ?
          MatrixIndex(x: 0, y: y + 1, columns: columns) :
          MatrixIndex(x: x + 1, y: y, columns: columns)
      }
    
      public func predecessor() -> MatrixIndex {
        return (x == 0) ?
          MatrixIndex(x: columns - 1, y: y - 1, columns: columns) :
          MatrixIndex(x: x - 1, y: y, columns: columns)
      }
    }
    
    public func == (lhs: MatrixIndex, rhs: MatrixIndex) -> Bool {
      return lhs.x == rhs.x && lhs.y == rhs.y
    }
    
    extension MatrixIndex : CustomDebugStringConvertible {
      public var debugDescription: String {
        return "\(x), \(y)"
      }
    }
    
    extension MatrixIndex: RandomAccessIndexType {
      public func advancedBy(n: Int) -> MatrixIndex {
        let total = (y * columns) + x + n
        return MatrixIndex(x: total % columns, y: total / columns, columns: columns)
      }
      public func distanceTo(other: MatrixIndex) -> Int {
        return (other.x - x) + (other.y - y) * columns
      }
    }
    

    Right. Now you’ll need another matrix struct:

    public struct Matrix2D<T> : MutableCollectionType {
      public var contents: [[T]]
      public subscript(index: MatrixIndex) -> T {
        get {
          return contents[index.y][index.x]
        } set {
          self.contents[index.y][index.x] = newValue
        }
      }
      public var count: Int { return contents[0].count * contents.count }
      public var startIndex: MatrixIndex {
        return MatrixIndex(x: 0, y: 0, columns: contents[0].count)
      }
      public var endIndex: MatrixIndex {
        return MatrixIndex(x: 0, y: contents.endIndex, columns: contents[0].count)
      }
    }
    

    Right. So now, after all of that, this works:

    let myMatrix = Matrix2D(contents: [[1, 2], [3, 4]])
    
    for (coordinate, value) in myMatrix.specEnumerate() {
      value == myMatrix[coordinate] // True every time
    }