Matrice bidimensională în Swift (Programare, Array-Uri, Swift)

Antiokhos a intrebat.

Sunt atât de confuz în legătură cu array-urile 2D în Swift. Permiteți-mi să vă descriu pas cu pas. Și vă rog să mă corectați dacă greșesc.

Mai întâi de toate; declararea unui array gol:

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

În al doilea rând umpleți array-ul. (cum ar fi my2Darr[i][j] = 0 unde i, j sunt variabilele for-loop)

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?  */
            }
        }
    }
}

Și, în cele din urmă, editarea elementului din matrice.

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

Comentarii

  • Aveți probleme cu abordarea dumneavoastră? –  > Por Alex Wayne.
  • Doar ca să știi, întregul pas al doilea poate fi redus la acest lucru var my2DArray = Array(count: 10, repeatedValue: Array(count: 10, repeatedValue: 18)) Și chiar ar trebui să faci upgrade la o versiune beta mai nouă. Int[][]() nu mai este o sintaxă valabilă. A fost schimbată în [[Int]](). –  > Por Mick MacCallum.
  • Init 2D care utilizează valori repetate nu va funcționa. Toate rândurile vor indica același sub-array și, prin urmare, nu vor putea fi scrise în mod unic. –  > Por hotpaw2.
8 răspunsuri
Keenle

Definiți array-ul mutabil

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

OR:

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

OR dacă aveți nevoie de un array de dimensiune predefinită (așa cum a menționat @0x7fffffffff în comentarii):

// 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)

Schimbați elementul la poziția

arr[0][1] = 18

OR

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

Modificați un subrețea

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

SAU

arr[0] += 234

OR

arr[0] += [345, 678]

Dacă înainte de aceste modificări aveați un tablou 3×2 de 0(zerouri), acum aveți:

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

Așadar, fiți atenți la faptul că subrețelele sunt mutabile și puteți redefini rețeaua inițială care a reprezentat matricea.

Examinați dimensiunea/limitele înainte de acces

let a = 0
let b = 1

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

Observații:Aceleași reguli de marcare pentru matricele cu 3 și N dimensiuni.

Comentarii

  • ok, o întrebare stupidă: cum atribuim această matrice, în C facem așa: arr[i][j]=myVar; dar în swift, când încerc să fac același lucru, am primit această eroare „[([(Int)])])].Type’ nu are un membru numit ‘subscript'” – –  > Por Antiokhos.
  • Dacă aveți arr definit ca în răspuns, atunci myVar ar trebui să fie Int, nu-i așa? –  > Por Keenle.
  • da, este int. Și vă mulțumesc foarte mult pentru răspunsul detaliat… acum este clar:D –  > Por Antiokhos.
  • În Swift 3, pentru cei care fac copy paste: var arr = Int(repeating: Int(repeating: 0, count: 2), count: 3) –  > Por kar.
  • În Swift 4.2: de exemplu,3 rânduri, 2 coloane, 3 * 2 var arr = Array(count: 2, repeatedValue: Array(count: 3, repeatedValue: 0)) –  > Por Zgpeace.
Woodstock

Din documente:

Puteți crea tablouri multidimensionale prin anidarea perechilor de paranteze pătrate, în care numele tipului de bază al elementelor este conținut în cea mai interioară pereche de paranteze pătrate. De exemplu, puteți crea o matrice tridimensională de numere întregi utilizând trei seturi de paranteze pătrate:

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

Atunci când se accesează elementele dintr-un tablou multidimensional, indicele de subscript cel mai din stânga se referă la elementul de la acel indice din tabloul cel mai exterior. Următorul indice de subscript din dreapta se referă la elementul de la acel indice din tabloul care se află la un nivel inferior. Și așa mai departe. Aceasta înseamnă că, în exemplul de mai sus, array3D[0] se referă la [[1, 2], [3, 4]]], array3D[0][1] se referă la [3, 4], iar array3D[0][1][1] se referă la valoarea 4.

dimohamdy

Faceți-o generică Swift 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])

Comentarii

Kimi Chiu

Ar trebui să fiți atenți atunci când folosiți Array(repeating: Array(repeating: {value}, count: 80), count: 24).

Dacă valoarea este un obiect, care este inițializat de către MyClass(), atunci acestea vor folosi aceeași referință.

Array(repeating: Array(repeating: MyClass(), count: 80), count: 24) nu creează o nouă instanță de MyClass în fiecare element al matricei. Această metodă creează doar MyClass o singură dată și o introduce în array.

Iată un mod sigur de a inițializa un array multidimensional.

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
}

Comentarii

  • Bună ziua, putem îmbunătăți acest lucru ca o extensie cu tipul „anyObject”? –  > Por Antiokhos.
  • Bună observație cu privire la problema cu tipurile de referință. Cu toate acestea, de ce scrieți Array(repeating: {value}, could 80) cu paranteze în jurul {value}? Asta ar crea o matrice de închideri, nu-i așa ? –  > Por Duncan C.
  • Sau este {value} meta-notație pentru „o valoare de tip AnyObject” (un tip de referință)? –  > Por Duncan C.
  • Am petrecut aproape o oră căutând un bug din cauza acestei probleme… –  > Por Matheus Weber.
garg

În Swift 4

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

Keyhan Kamangar

Conform documentelor Apple pentru swift 4.1, puteți utiliza acest struct atât de ușor pentru a crea o matrice 2D:

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

Exemplu de cod:

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
        }
    }
}

Comentarii

  • Îmi place. Este o reminiscență a aritmeticii pointerilor din C. Totuși, ar fi mai bine dacă ar fi rescrisă folosind Generics, astfel încât să se aplice la array-uri bidimensionale de orice tip de date. De altfel, ați putea folosi această abordare pentru a crea array-uri de orice dimensiune arbitrară. –  > Por Duncan C.
  • @vacawama, mișto, doar că matricea ta n-dimensională are aceeași problemă ca toate soluțiile care populează matricea folosind Array(repeating:count:). Vezi comentariul pe care l-am postat la celălalt răspuns al tău. –  > Por Duncan C.
Karoly Nyisztor

Înainte de a utiliza array-uri multidimensionale în Swift, luați în considerare impactul acestora asupra performanței. În testele mele, matricea aplatizată a avut performanțe de aproape 2 ori mai bune decât versiunea 2D:

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
    }
}

Timpul mediu de execuție pentru umplerea unui Array 50×50: 82,9ms

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
    }
}

Timpul mediu de execuție pentru umplerea unui Array 2D de 50×50: 135ms

Amândoi algoritmii sunt O(n^2), astfel încât diferența de timp de execuție este cauzată de modul în care inițializăm tabelul.

În cele din urmă, se poate observa că cel mai rău pe care o puteți face este să folosiți append() pentru a adăuga noi elemente. Aceasta s-a dovedit a fi cea mai lentă în testele mele:

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

Timpul mediu de execuție pentru umplerea unui Array 50×50 folosind append(): 2,59s.

Concluzie

Evitați array-urile multidimensionale și utilizați accesul prin index dacă viteza de execuție contează. Array-urile 1D sunt mai performante, dar codul dumneavoastră ar putea fi puțin mai greu de înțeles.

Puteți rula singuri testele de performanță după ce descărcați proiectul demo din repo-ul meu GitHub: https://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground

pimisi

Acest lucru se poate face într-o singură linie simplă.

Swift 5

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

De asemenea, ați putea să o mapezi la instanțe ale oricărei clase sau structuri la alegere

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)}
}