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) { ...  }   */
    }
}
Antiokhos
quelle
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.

Keenle
quelle
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.

Holzlager
quelle
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])
Dimo Hamdy
quelle
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
}
Kimi Chiu
quelle
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]]
Ankit garg
quelle
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
        }
    }
}
Keyhan Kamangar
quelle
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

Karoly Nyisztor
quelle
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)}
}
pimisi
quelle