Swiftの2次元配列


109

Swiftの2D配列について混乱しています。ステップバイステップで説明します。そして、私が間違っているなら、私を訂正してください。

まず第一に; 空の配列の宣言:

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

次に、配列を埋めます。(my2Darr[i][j] = 0ここで、i、jはforループ変数など)

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

そして最後に、配列内の要素の編集

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

アプローチに問題がありますか?
Alex Wayne

2
ご存知のように、2番目のステップ全体をこれまでに減らすことができます。var my2DArray = Array(count: 10, repeatedValue: Array(count: 10, repeatedValue: 18))そして、新しいベータに本当にアップグレードする必要があります。Int[][]()は有効な構文ではなくなりました。に変更されました[[Int]]()
Mick MacCallum 14

1
繰り返し値を使用する2D initは機能しません。すべての行は同じサブ配列を指すため、一意に書き込むことはできません。
hotpaw2 14

回答:


228

可変配列を定義する

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

または:

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

または、事前定義されたサイズの配列が必要な場合(@ 0x7fffffffでコメントに記載されているように):

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

位置の要素を変更

arr[0][1] = 18

または

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

サブ配列を変更

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

または

arr[0] += 234

または

arr[0] += [345, 678]

これらの変更の前に0(ゼロ)の3x2配列があった場合、次のようになります。

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

したがって、サブ配列は変更可能であり、行列を表す初期配列を再定義できることに注意してください。

アクセスする前にサイズ/境界を調べます

let a = 0
let b = 1

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

備考: 3次元配列とN次元配列のマークアップ規則は同じです。


いい質問です。配列を割り当てる方法、Cでは次のようにします。arr[i] [j] = myVar; しかし、同じようにしようとすると、このエラー「 '[([(Int)])]。Type'に「添え字」という名前のメンバーがありません
Antiokhos

あなたがarr答えのように定義したmyVarなら、それはIntであるべきです、そうですか?
Keenle 2014

はい、それはintです。そして、詳細な回答をありがとうございました。現在、明確です:D
Antiokhos 2014

6
Swift 3では、コピーペーストの場合:var arr = Int(repeating: Int(repeating: 0, count: 2), count: 3)
kar

1
Swift 4.2の場合:たとえば、3行、2列、3 * 2var arr = Array(count: 2, repeatedValue: Array(count: 3, repeatedValue: 0))
Zgpeace

27

ドキュメントから:

角括弧のペアをネストすることにより、多次元配列を作成できます。要素の基本タイプの名前は、角括弧の最も内側のペアに含まれています。たとえば、3組の角括弧を使用して整数の3次元配列を作成できます。

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

多次元配列の要素にアクセスする場合、左端の添字インデックスは、最も外側の配列のそのインデックスにある要素を参照します。右側の次の添え字インデックスは、1レベルでネストされた配列内のそのインデックスにある要素を参照します。以下同様に続きます。つまり、上記の例では、array3D [0]は[[1、2]、[3、4]]を指し、array3D [0] [1]は[3、4]を指し、array3D [0] [1 ] [1]は値4を参照します。


17

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

私は2Dトロイダル配列を作成するためにあなたの答えを採用しました。どうもありがとう!gist.github.com/amiantos/bb0f313da1ee686f4f69b8b44f3cd184
Brad Root

16

を使用するときは注意が必要ですArray(repeating: Array(repeating: {value}, count: 80), count: 24)

値がによって初期化されるオブジェクトである場合、それらはMyClass()同じ参照を使用します。

Array(repeating: Array(repeating: MyClass(), count: 80), count: 24)MyClass各配列要素にの新しいインスタンスを作成しません。このメソッドはMyClass一度だけ作成し、それを配列に入れます。

多次元配列を初期化する安全な方法を次に示します。

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
}

こんにちは、「anyObject」タイプの拡張機能としてそれを改善できますか?
アンティオコス

参照型の問題についての良い点。しかし、なぜArray(repeating: {value}, could 80)中括弧で書くの{value}ですか?それはクロージャーの配列を作成しますが、そうではありませんか?
Duncan C

または{value}、「AnyObjectタイプのいくつかの値」(参照タイプ)のメタ表記ですか?
ダンカンC

この問題のため、1時間近くバグを探していました...
Matheus Weber


10

Swift 4.1のAppleドキュメントによると、この構造体を使用して2D配列を簡単に作成できます。

リンク:https : //developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html

コードサンプル:

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
私はそれが好きです。これは、Cポインター演算を連想させます。ただし、Genericsを使用して書き換えたほうがよいため、任意のデータ型の2次元配列に適用されます。さらに言えば、このアプローチを使用して、任意の次元の配列を作成できます。
ダンカンC

1
@vacawama、クール、ただしn次元配列には、を使用して配列にデータを入力するすべてのソリューションと同じ問題がありArray(repeating:count:)ます。他の回答に投稿したコメントをご覧ください。
ダンカンC

6

Swiftで多次元配列を使用する前に、パフォーマンスへの影響を考慮してください。私のテストでは、フラット化されたアレイのパフォーマンスは2Dバージョンのほぼ2倍です。

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アレイを満たすための平均実行時間:82.9ms

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 2Dアレイを満たすための平均実行時間:135ms

どちらのアルゴリズムもO(n ^ 2)であるため、実行時間の違いは、テーブルの初期化方法によって発生します。

最後に、あなたができる最悪のことはappend()、新しい要素を追加するために使用することです。それが私のテストで最も遅いことがわかりました:

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

append()を使用して50x50配列を満たすための平均実行時間:2.59秒

結論

実行速度が重要な場合は、多次元配列を避け、インデックスによるアクセスを使用してください。1D配列の方がパフォーマンスは優れていますが、コードを理解するのが少し難しい場合があります。

GitHubリポジトリからデモプロジェクトをダウンロードした後、自分でパフォーマンステストを実行できます。https//github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground


0

これは1行で行うことができます。

スウィフト5

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

また、任意のクラスまたは構造体のインスタンスにマッピングすることもできます

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)}
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.