programing

스위프트의 2차원 배열

telecom 2023. 8. 23. 21:36
반응형

스위프트의 2차원 배열

Swift의 2D 어레이에 대해 너무 혼란스럽습니다.단계별로 설명하겠습니다.그리고 제가 틀렸다면 수정해 주시겠습니까?

우선, 빈 배열 선언:

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

두 번째로 배열을 채웁니다.(예:my2Darr[i][j] = 0여기서 i, jare 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?  */
            }
        }
    }
}

그리고 마지막으로, inarray의 요소를 편집합니다.

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

가변 배열 정의

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

OR:

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

또는 미리 정의된 크기의 배열이 필요한 경우(댓글에서 @0x7ffffff가 언급한 대로):

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

OR

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

하위 배열 변경

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

OR

arr[0] += 234

OR

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차원 배열에 대한 동일한 마크업 규칙.

문서에서:

요소의 기본 유형 이름이 가장 안쪽의 대괄호 쌍에 포함된 대괄호 쌍을 중첩하여 다차원 배열을 만들 수 있습니다.예를 들어, 세 개의 대괄호 집합을 사용하여 3차원 정수 배열을 만들 수 있습니다.

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

다차원 배열의 요소에 액세스할 때 가장 왼쪽에 있는 첨자 인덱스는 가장 바깥쪽 배열의 해당 인덱스에 있는 요소를 참조합니다.오른쪽의 다음 첨자 인덱스는 배열에서 한 수준으로 중첩된 해당 인덱스의 요소를 나타냅니다.등등.이것은 위의 예에서 배열3을 의미합니다.D[0]는 [1, 2], [3, 4], 배열 3을 말합니다.D[0][1]은 [3, 4]를 참조하며 배열3D[0][1][1]은 값 4를 나타냅니다.

제네릭 스위프트 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])

사용할 때는 주의해야 합니다.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
}

인 스위프트 4

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

Apple의 swift 4.1 문서에 따르면 이 구조를 매우 쉽게 사용하여 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
        }
    }
}

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 repo: https://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground 에서 데모 프로젝트를 다운로드한 후 직접 성능 테스트를 실행할 수 있습니다.

Swift 5.5에서

2D 어레이를 어떻게 장착할 수 있는지 이해하기 위한 것입니다.

enter image description here

import UIKit

var greeting = "Hello, playground"

var arrXY = [[String]]()

//             0   1   2   3
arrXY.append(["A","B","C","D"]) // 0
arrXY.append(["E","F","G","H"]) // 1
arrXY.append(["J","K","L","M"]) // 2
arrXY.append(["N","O","P","Q"]) // 3

print(arrXY)

print(arrXY[2][1]) // xy(2,1)
print(arrXY[0][3]) // xy(0,3)
print(arrXY[3][3]) // xy(3,3)

이 작업은 한 줄로 간단하게 수행할 수 있습니다.

스위프트 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)}
}

Swift 버전 5.5

이 버전에서는 기본 옵션 배열을 사용하여 어설션 사용으로 인해 발생할 수 있는 런타임 오류를 방지합니다.

struct Matrix<T> {
  let numberOfRows: Int
  let numberOfColumns: Int
  
  var elements: [T?]
  
  /// Creates a new matrix whose size is defined by the specified number of rows and columns.
  /// containing a single, repeated optional value.
  ///
  ///  - Parameters:
  ///    - repeatedValue: The element to repeat
  ///    - numberOfRows: The number of rows
  ///    - numberOfColumns: The number of columns
  init(repeating repeatedValue: T? = nil, numberOfRows: Int, numberOfColumns: Int) {
    // counts must be zero or greater.
    let numberOfRows = numberOfRows > 0 ? numberOfRows : 0
    let numberOfColumns = numberOfColumns > 0 ? numberOfColumns : 0
    
    self.numberOfRows = numberOfRows
    self.numberOfColumns = numberOfColumns
    self.elements = Array(repeating: repeatedValue, count: numberOfRows * numberOfColumns)
  }
  
  subscript(row: Int, column: Int) -> T? {
    get { elements[(row * numberOfColumns) + column] }
    set { elements[(row * numberOfColumns) + column] = newValue }
  }
}

저는 1D 어레이를 사용하고 인덱스만 따로 작성할 것입니다.예를 들어 다음을 사용해 보십시오.

struct MatrixIndexer {
    var rows: Int
    var columns: Int
    
    var count: Int {
        return rows * columns
    }
    
    subscript(_ r: Int, _ c: Int) -> Int {
        precondition(r < rows && c < columns)
        return r * columns + c
    }
    
    func coordinate(_ i: Int) -> (row: Int, column: Int) {
        precondition(i < count)
        return (i / columns, i % columns)
    }
}

let at = MatrixIndexer(rows: 16, columns: 8)
var array2D: [Float] = Array(repeating: 0, count: at.count)

array2D[at[3, 4]] = 3
array2D[at[5, 2]] = 6

(단일구을통려면다같입다니합력이음과키시과물조)▁(다▁an▁(단니▁to입▁you합력▁introduce▁struct▁around,같▁single▁you이▁couldif▁pass)를 도입할 수 있습니다.Array2D를포는하가 .MatrixIndexer 리고그.Array).

왜 이게 좋은 생각일까요?첫째, 다음과 같은 보다 효율적인 운영이 가능합니다.

  • 컬렉션 확장명: 맵, 필터, 축소
  • 단일 루프에서 모든 요소 반복
  • 쉬운 복사
  • 각 행과 열의 크기가 동일한지 여부를 확인합니다.

둘째로, 그것은 또한 성능 면에서도 훨씬 더 좋습니다.

  • 메모리 할당을 줄임으로써 액세스 시간을 단축합니다.각 행이 메모리에서 별도의 점이 되는 대신 각 요소는 다음 요소와 인접합니다.
  • 많은 명령 대신 하나의 할당 및 할당 취소 명령을 사용합니다(할당자는 다양한 이유로 느려지는 경우가 많습니다).

당신이 사용한다면 때때로 그것은 일을 더 간단하게 만드는 것을 도울 수 있습니다.typealias기본 배열 유형에 해당합니다.은 은다음 2D 예니다의 입니다.String:

typealias Strings = [String]

let stringGroups: [Strings] // aka [[String]]

언급URL : https://stackoverflow.com/questions/25127700/two-dimensional-array-in-swift

반응형