Zweidimensionales Array in Swift


109

Ich bin so verwirrt über 2D-Arrays in Swift. Lassen Sie mich Schritt für Schritt beschreiben. Und würden Sie mich bitte korrigieren, wenn ich falsch liege?

Zuerst; Deklaration eines leeren Arrays:

class test{
    var my2Darr = Int[][]()
}

Zweitens füllen Sie das Array. (z. B. my2Darr[i][j] = 0wo i, j for-Schleifenvariablen sind)

class test {
    var my2Darr = Int[][]()
    init() {
        for(var i:Int=0;i<10;i++) {
            for(var j:Int=0;j<10;j++) {
                my2Darr[i][j]=18   /*  Is this correct?  */
            }
        }
    }
}

Und schließlich das Element Bearbeiten im Array

class test {
    var my2Darr = Int[][]()
    init() {
        ....  //same as up code
    }
    func edit(number:Int,index:Int){
        my2Darr[index][index] = number
        // Is this correct? and What if index is bigger
        // than i or j... Can we control that like 
        if (my2Darr[i][j] == nil) { ...  }   */
    }
}

Haben Sie Probleme mit Ihrem Ansatz?
Alex Wayne

2
Nur damit Sie wissen, kann Ihr gesamter zweiter Schritt darauf reduziert werden. var my2DArray = Array(count: 10, repeatedValue: Array(count: 10, repeatedValue: 18))Und Sie sollten wirklich auf eine neuere Beta upgraden. Int[][]()ist keine gültige Syntax mehr. Es wurde geändert in [[Int]]().
Mick MacCallum

1
Der 2D-Init mit wiederholten Werten funktioniert nicht. Alle Zeilen verweisen auf dasselbe Unterarray und sind daher nicht eindeutig beschreibbar.
hotpaw2

Antworten:


228

Definieren Sie ein veränderliches Array

// 2 dimensional array of arrays of Ints 
var arr = [[Int]]() 

ODER:

// 2 dimensional array of arrays of Ints 
var arr: [[Int]] = [] 

ODER wenn Sie ein Array mit vordefinierter Größe benötigen (wie von @ 0x7fffffff in den Kommentaren erwähnt):

// 2 dimensional array of arrays of Ints set to 0. Arrays size is 10x5
var arr = Array(count: 3, repeatedValue: Array(count: 2, repeatedValue: 0))

// ...and for Swift 3+:
var arr = Array(repeating: Array(repeating: 0, count: 2), count: 3)

Element an Position ändern

arr[0][1] = 18

ODER

let myVar = 18
arr[0][1] = myVar

Unterarray ändern

arr[1] = [123, 456, 789] 

ODER

arr[0] += 234

ODER

arr[0] += [345, 678]

Wenn Sie vor diesen Änderungen ein 3x2-Array mit 0 (Nullen) hatten, haben Sie jetzt:

[
  [0, 0, 234, 345, 678], // 5 elements!
  [123, 456, 789],
  [0, 0]
]

Beachten Sie also, dass Sub-Arrays veränderbar sind und Sie das ursprüngliche Array, das die Matrix darstellt, neu definieren können.

Untersuchen Sie Größe / Grenzen vor dem Zugriff

let a = 0
let b = 1

if arr.count > a && arr[a].count > b {
    println(arr[a][b])
}

Anmerkungen: Gleiche Markup-Regeln für 3- und N-dimensionale Arrays.


ok eine dumme Frage: wie wir dieses Array zuweisen, In C gefällt uns das: arr [i] [j] = myVar; aber schnell, wenn ich versuche, auf die gleiche Weise zu tun, bekam ich diesen Fehler "'[([(Int)])]. Typ' hat kein Mitglied namens 'tiefgestellt'"
Antiokhos

Wenn Sie arrwie in der Antwort definiert haben , myVarsollte dann Int sein, oder?
Keenle

ja es ist int. Und vielen Dank für die ausführliche Antwort. Jetzt ist klar: D
Antiokhos

6
In Swift 3 für Copy Pasters:var arr = Int(repeating: Int(repeating: 0, count: 2), count: 3)
Kar

1
In Swift 4.2: zum Beispiel 3 Zeilen, 2 Spalten, 3 * 2var arr = Array(count: 2, repeatedValue: Array(count: 3, repeatedValue: 0))
Zgpeace

27

Aus den Dokumenten:

Sie können mehrdimensionale Arrays erstellen, indem Sie Paare eckiger Klammern verschachteln, wobei der Name des Basistyps der Elemente im innersten Paar eckiger Klammern enthalten ist. Sie können beispielsweise ein dreidimensionales Array von Ganzzahlen mit drei Sätzen eckiger Klammern erstellen:

var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

Beim Zugriff auf die Elemente in einem mehrdimensionalen Array bezieht sich der Index ganz links auf das Element an diesem Index im äußersten Array. Der nächste tiefgestellte Index rechts bezieht sich auf das Element an diesem Index in dem Array, in dem eine Ebene verschachtelt ist. Und so weiter. Dies bedeutet, dass sich Array3D [0] im obigen Beispiel auf [[1, 2], [3, 4]], Array3D [0] [1] auf [3, 4] und Array3D [0] [1] bezieht ] [1] bezieht sich auf den Wert 4.


17

Machen Sie es generisch schnell 4

struct Matrix<T> {
    let rows: Int, columns: Int
    var grid: [T]
    init(rows: Int, columns: Int,defaultValue: T) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeating: defaultValue, count: rows * columns) as! [T]
    }
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> T {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}


var matrix:Matrix<Bool> = Matrix(rows: 1000, columns: 1000,defaultValue:false)

matrix[0,10] = true


print(matrix[0,10])

Ich habe Ihre Antwort angepasst, um ein 2D-Ringarray zu erstellen. Vielen Dank! gist.github.com/amiantos/bb0f313da1ee686f4f69b8b44f3cd184
Brad Root

16

Sie sollten vorsichtig sein, wenn Sie verwenden Array(repeating: Array(repeating: {value}, count: 80), count: 24).

Wenn der Wert ein Objekt ist, das von initialisiert wird MyClass(), verwenden sie dieselbe Referenz.

Array(repeating: Array(repeating: MyClass(), count: 80), count: 24)erstellt nicht MyClassin jedem Array-Element eine neue Instanz von . Diese Methode wird nur MyClasseinmal erstellt und in das Array eingefügt.

Hier ist eine sichere Möglichkeit, ein mehrdimensionales Array zu initialisieren.

private var matrix: [[MyClass]] = MyClass.newMatrix()

private static func newMatrix() -> [[MyClass]] {
    var matrix: [[MyClass]] = []

    for i in 0...23 {
        matrix.append( [] )

        for _ in 0...79 {
            matrix[i].append( MyClass() )
        }
    }

    return matrix
}

Hallo, können wir das als Erweiterung mit dem Typ "anyObject" verbessern?
Antiokhos

Guter Punkt zum Problem mit Referenztypen. Warum schreibst du jedoch Array(repeating: {value}, could 80)mit geschweiften Klammern {value}? Das würde eine Reihe von Verschlüssen schaffen, nicht wahr?
Duncan C

Oder ist {value}Meta-Notation für "einen Wert vom Typ AnyObject" (ein Referenztyp)?
Duncan C

Ich habe fast eine Stunde damit verbracht, nach einem Fehler wegen dieses Problems zu suchen ...
Matheus Weber

13

In Swift 4

var arr = Array(repeating: Array(repeating: 0, count: 2), count: 3)
// [[0, 0], [0, 0], [0, 0]]

10

Laut Apple-Dokumenten für Swift 4.1 können Sie diese Struktur so einfach verwenden, um ein 2D-Array zu erstellen:

Link: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html

Codebeispiel:

struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeating: 0.0, count: rows * columns)
    }
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

1
Ich mag das. Es erinnert an die C-Zeiger-Arithmetik. Es wäre jedoch besser, wenn Generics neu geschrieben würde, damit es für zweidimensionale Arrays eines beliebigen Datentyps gilt. Mit diesem Ansatz können Sie Arrays beliebiger Dimension erstellen.
Duncan C

1
@vacawama, cool, außer dass Ihr n-dimensionales Array das gleiche Problem hat wie alle Lösungen, die das Array mit füllen Array(repeating:count:). Siehe den Kommentar, den ich zu Ihrer anderen Antwort gepostet habe.
Duncan C

6

Berücksichtigen Sie vor der Verwendung mehrdimensionaler Arrays in Swift deren Auswirkungen auf die Leistung . In meinen Tests schnitt das abgeflachte Array fast zweimal besser ab als die 2D-Version:

var table = [Int](repeating: 0, count: size * size)
let array = [Int](1...size)
for row in 0..<size {
    for column in 0..<size {
        let val = array[row] * array[column]
        // assign
        table[row * size + column] = val
    }
}

Durchschnittliche Ausführungszeit zum Auffüllen eines 50x50-Arrays: 82,9 ms

vs.

var table = [[Int]](repeating: [Int](repeating: 0, count: size), count: size)
let array = [Int](1...size)
for row in 0..<size {
    for column in 0..<size {
        // assign
        table[row][column] = val
    }
}

Durchschnittliche Ausführungszeit zum Auffüllen eines 50x50 2D-Arrays: 135 ms

Beide Algorithmen sind O (n ^ 2), daher wird der Unterschied in den Ausführungszeiten durch die Art und Weise verursacht, wie wir die Tabelle initialisieren.

Das Schlimmste, was Sie tun können, ist append(), neue Elemente hinzuzufügen. Das war das langsamste in meinen Tests:

var table = [Int]()    
let array = [Int](1...size)
for row in 0..<size {
    for column in 0..<size {
        table.append(val)
    }
}

Durchschnittliche Ausführungszeit zum Auffüllen eines 50x50-Arrays mit append (): 2,59 s

Fazit

Vermeiden Sie mehrdimensionale Arrays und verwenden Sie den Zugriff per Index, wenn die Ausführungsgeschwindigkeit von Bedeutung ist. 1D-Arrays sind leistungsfähiger, aber Ihr Code ist möglicherweise etwas schwieriger zu verstehen.

Sie können die Leistungstests selbst ausführen, nachdem Sie das Demo-Projekt von meinem GitHub-Repo heruntergeladen haben: https://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground


0

Dies kann in einer einfachen Zeile erfolgen.

Swift 5

var my2DArray = (0..<4).map { _ in Array(0..<) }

Sie können es auch Instanzen einer Klasse oder Struktur Ihrer Wahl zuordnen

struct MyStructCouldBeAClass {
    var x: Int
    var y: Int
}

var my2DArray: [[MyStructCouldBeAClass]] = (0..<2).map { x in
    Array(0..<2).map { MyStructCouldBeAClass(x: x, y: $0)}
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.