2014-10-25 7 views
6

Ich muss in der Lage sein, Informationen über Zellen in einer 2D-Matrix oder einem Gitter zu speichern. Die Daten sind nicht zusammenhängend, daher muss ich möglicherweise Daten bei 5,5 speichern, wenn in den unteren Zeilen und Spalten keine Daten vorhanden sind.Swift: Wie man ein 2d-Array (Gitter oder Matrix) in Swift deklariert, um zufälliges Einfügen zu ermöglichen

Mein erster Gedanke war ein Array von Arrays dynamisch Größe. Aber Swift-Arrays haben Grenzen, die nicht automatisch wachsen. Wenn ich versuche, etwas an Index 5 zu platzieren, und das über seine aktuelle Größe hinausgeht, scheitert es an der Ausnahmesperre.

Gibt es in Swift oder Cocoa eine Erfassungsklasse, die den wahlfreien Zugriff auf ein Gitter unterstützt. NSArray unterstützt es auch nicht.

Ein anderer Gedanke war, die Elemente in einem Wörterbuch zu speichern und ein Tupel von Zeile, Spalte als Schlüssel zu verwenden. Tupel sind jedoch nicht hashbar und können nicht als Schlüssel für ein Wörterbuch verwendet werden.

Mein aktueller Ansatz besteht darin, das Array mit einer festgelegten Größe, die mit Nullen gefüllt ist, vorinitialisieren. Gibt es einen besseren Weg?

Antwort

4

Hier ist eine sehr einfache Implementierung, Dictionary als Back-End-Speicher mit:

struct Matrix2D<KeyElem:Hashable, Value> { 

    var _storage:[KeyElem:[KeyElem:Value]] = [:] 

    subscript(x:KeyElem, y:KeyElem) -> Value? { 
     get { 
      return _storage[x]?[y] 
     } 
     set(val) { 
      if _storage[x] == nil { 
       _storage[x] = [:] 
      } 
      _storage[x]![y] = val 
     } 
    } 
} 

var matrix = Matrix2D<Int, String>() 

matrix[1,2] = "foo" 

als DictionaryLiteralConvertible:

extension Matrix2D:DictionaryLiteralConvertible { 

    typealias Key = (x:KeyElem, y:KeyElem) 

    init(dictionaryLiteral elements: (Key, Value)...) { 
     for (key, val) in elements { 
      self[key.x, key.y] = val 
     } 
    } 
} 

var matrix:Matrix2D = [(1,2):"foo", (2,3):"bar"] 

Array Backend-Version

struct Matrix2D<T> { 

    var _storage:[[T?]] = [] 

    subscript(x:Int, y:Int) -> T? { 
     get { 
      if _storage.count <= x { 
       return nil 
      } 
      if _storage[x].count <= y { 
       return nil 
      } 
      return _storage[x][y] 
     } 
     set(val) { 
      if _storage.count <= x { 
       let cols = [[T?]](count: x - _storage.count + 1, repeatedValue: []) 
       _storage.extend(cols) 
      } 
      if _storage[x].count <= y { 
       let rows = [T?](count: y - _storage[x].count + 1, repeatedValue: nil) 
       _storage[x].extend(rows) 
      } 
      _storage[x][y] = val 
     } 
    } 
} 
+0

Großartig! Vielen Dank. Ich kann dem Array-Backend folgen, aber nicht dem Wörterbuch-Backend folgen. – David

Verwandte Themen