Swift'de iki boyutlu dizi


109

Swift'deki 2B diziler hakkında kafam çok karışıyor. Adım adım anlatayım. Ve yanılıyorsam lütfen beni düzeltir misin?

Her şeyden önce; boş bir dizinin bildirimi:

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

İkinci olarak diziyi doldurun. ( my2Darr[i][j] = 0i, j'nin for-döngü değişkenleri olduğu gibi)

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

Ve Son olarak, dizideki düzenleme öğesi

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

Yaklaşımınızla ilgili sorunlar mı yaşıyorsunuz?
Alex Wayne

2
Bildiğiniz gibi, ikinci adımınızın tamamı buna indirgenebilir var my2DArray = Array(count: 10, repeatedValue: Array(count: 10, repeatedValue: 18))Ve gerçekten daha yeni bir beta sürümüne geçmelisiniz. Int[][]()artık geçerli sözdizimi değil. Olarak değiştirildi [[Int]]().
Mick MacCallum

1
Tekrarlanan değerleri kullanan 2D init çalışmaz. Tüm satırlar aynı alt diziyi gösterecek ve bu nedenle benzersiz bir şekilde yazılamayacaktır.
hotpaw2

Yanıtlar:


228

Değiştirilebilir dizi tanımlayın

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

VEYA:

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

VEYA önceden tanımlanmış boyutta bir diziye ihtiyacınız varsa (yorumlarda @ 0x7fffffff tarafından belirtildiği gibi):

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

Öğeyi konumunda değiştir

arr[0][1] = 18

VEYA

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

Alt diziyi değiştir

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

VEYA

arr[0] += 234

VEYA

arr[0] += [345, 678]

Bu değişikliklerden önce 3x2 0 (sıfır) dizisine sahipseniz, şimdi şunlara sahipsiniz:

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

Bu nedenle, alt dizilerin değiştirilebilir olduğunu ve matrisi temsil eden ilk diziyi yeniden tanımlayabileceğinizi unutmayın.

Erişimden önce boyutu / sınırları inceleyin

let a = 0
let b = 1

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

Açıklamalar: 3 ve N boyutlu diziler için aynı biçimlendirme kuralları.


ok aptal bir soru: bu diziyi nasıl atarız, C'de şöyle yaparız: arr [i] [j] = myVar; ama aynı şekilde yapmaya çalıştığımda hızlı bir şekilde bu hatayı aldım "'[([(Int)])].'
türünde

Eğer varsa arrcevap olarak tanımlanan sonra myVarInt olmalıdır, değil mi?
Keenle

evet int. Ve detaylı cevap için çok teşekkür ederim .. şimdi açık: D
Antiokhos

6
Swift 3'te kopya pasters için:var arr = Int(repeating: Int(repeating: 0, count: 2), count: 3)
kar

1
Swift 4.2'de: örneğin, 3 satır, 2 sütun, 3 * 2var arr = Array(count: 2, repeatedValue: Array(count: 3, repeatedValue: 0))
Zgpeace

27

Dokümanlardan:

Çok boyutlu diziler, köşeli parantez çiftlerini iç içe yerleştirerek oluşturabilirsiniz; burada, öğelerin temel türünün adı en içteki köşeli parantez çiftinde bulunur. Örneğin, üç köşeli parantez kullanarak üç boyutlu bir tamsayı dizisi oluşturabilirsiniz:

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

Çok boyutlu bir dizideki öğelere erişirken, en soldaki alt simge dizini, en dış dizideki o dizindeki öğeyi ifade eder. Sağdaki bir sonraki alt simge dizini, dizide bir düzey içinde yuvalanmış olan dizindeki öğeyi ifade eder. Bu, yukarıdaki örnekte, dizi3D [0] 'nın [[1, 2], [3, 4]]' e, dizi3D [0] [1] 'nin [3, 4]' e ve dizi3D [0] [1 ] [1] 4 değerini ifade eder.


17

Jenerik Swift 4 yap

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

Cevabınızı 2D toroidal bir dizi oluşturacak şekilde uyarladım. Çok teşekkürler! gist.github.com/amiantos/bb0f313da1ee686f4f69b8b44f3cd184
Brad Root

16

Kullanırken dikkatli olmalısın Array(repeating: Array(repeating: {value}, count: 80), count: 24).

Değer, tarafından başlatılan bir nesneyse, MyClass()aynı referansı kullanırlar.

Array(repeating: Array(repeating: MyClass(), count: 80), count: 24)MyClassher dizi öğesinde yeni bir örnek oluşturmaz . Bu yöntem yalnızca bir MyClasskez oluşturur ve diziye yerleştirir.

İşte çok boyutlu bir diziyi başlatmanın güvenli bir yolu.

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
}

Merhaba, bunu "anyObject" türünde bir uzantı olarak geliştirebilir miyiz?
Antiokhos'a

Referans türleriyle ilgili problem hakkında iyi bir nokta. Ancak neden Array(repeating: {value}, could 80)etrafına parantez ile yazıyorsun {value}? Bu bir dizi kapanış yaratır, değil mi?
Duncan C

Veya {value}"AnyObject türünde bir değer" (bir başvuru türü) için meta gösterim mi?
Duncan C

Bu problem yüzünden neredeyse bir saatimi bir böcek aramakla geçirdim ...
Matheus Weber

13

Swift 4'te

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

10

Apple'ın hızlı 4.1 belgelerine göre, bu yapıyı 2D bir dizi oluşturmak için çok kolay bir şekilde kullanabilirsiniz:

Bağlantı: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html

Kod örneği:

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
Bunu sevdim. C işaretçisi aritmetiğini anımsatıyor. Genetikler kullanılarak yeniden yazılırsa daha iyi olur, bu nedenle herhangi bir veri türünün 2 boyutlu dizileri için geçerli olur. Bu nedenle, herhangi bir boyutta diziler oluşturmak için bu yaklaşımı kullanabilirsiniz.
Duncan C

1
@vacawama, harika, ancak n boyutlu diziniz, diziyi kullanan tüm çözümlerle aynı soruna sahip Array(repeating:count:) . Diğer cevabınıza gönderdiğim yorumu görün.
Duncan C

6

Swift'de çok boyutlu dizileri kullanmadan önce , performans üzerindeki etkilerini düşünün . Testlerimde, düzleştirilmiş dizi 2D sürümden neredeyse 2 kat daha iyi performans gösterdi:

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

50x50'lik bir Diziyi doldurmak için ortalama yürütme süresi: 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
    }
}

50x50'lik bir 2D Diziyi doldurmak için ortalama yürütme süresi: 135 ms

Her iki algoritma da O (n ^ 2) 'dir, dolayısıyla yürütme sürelerindeki fark tabloyu başlatma şeklimizden kaynaklanır.

Son olarak yapabileceğiniz kötü şey, append()yeni öğeler eklemek için kullanmaktır . Testlerimde en yavaş olduğunu kanıtladı:

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

Append () kullanılarak 50x50'lik bir Diziyi doldurmak için ortalama yürütme süresi: 2,59 sn

Sonuç

Çok boyutlu dizilerden kaçının ve yürütme hızı önemliyse dizine göre erişimi kullanın. 1D dizileri daha performanslıdır, ancak kodunuzun anlaşılması biraz daha zor olabilir.

Demo projesini GitHub depomdan indirdikten sonra performans testlerini kendiniz çalıştırabilirsiniz: https://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground


0

Bu, tek bir satırda yapılabilir.

Swift 5

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

İstediğiniz herhangi bir sınıfın veya yapının örnekleriyle de eşleyebilirsiniz.

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)}
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.