Swift의 2 차원 배열


109

Swift의 2D 배열에 대해 너무 혼란 스러워요. 단계별로 설명하겠습니다. 그리고 제가 틀렸다면 제발 정정 해 주시겠습니까?

가장 먼저; 빈 배열 선언 :

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

두 번째로 배열을 채 웁니다. (예를 들어 my2Darr[i][j] = 0i, 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
아시다시피, 두 번째 단계 전체를이 단계로 줄일 수 있습니다 var my2DArray = Array(count: 10, repeatedValue: Array(count: 10, repeatedValue: 18)). 새로운 베타 버전으로 업그레이드해야합니다. Int[][]()더 이상 유효한 구문이 아닙니다. 로 변경되었습니다 [[Int]]().
Mick MacCallum 2014-08-04

1
반복되는 값을 사용하는 2D 초기화는 작동하지 않습니다. 모든 행은 동일한 하위 배열을 가리 키므로 고유하게 쓸 수 없습니다.
hotpaw2 2014-08-04

답변:


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)를])] 입력하십시오.'"
Antiokhos

arr대답에서와 같이 정의 했다면 myVarInt 여야합니까?
Keenle 2014-08-05

네, 정수입니다. D : 그리고 지금 ... 자세한 답변을 아주 많이는 명확 감사합니다
Antiokhos

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 차원 배열을 만들 수 있습니다.

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

다차원 배열의 요소에 액세스 할 때 가장 왼쪽에있는 첨자 인덱스는 가장 바깥 쪽 배열의 해당 인덱스에있는 요소를 참조합니다. 오른쪽에있는 다음 아래 첨자 인덱스는 한 수준에 중첩 된 배열의 해당 인덱스에있는 요소를 나타냅니다. 등등. 즉, 위의 예에서 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"유형의 확장으로 개선 할 수 있습니까?
Antiokhos

참조 유형 문제에 대한 좋은 점입니다. 그러나 왜 Array(repeating: {value}, could 80)중괄호로 작성 {value}합니까? 그것은 일련의 클로저를 생성 할 것입니다.
Duncan C

아니면 {value}"AnyObject 유형의 일부 값"(참조 유형)에 대한 메타 표기법입니까?
Duncan C

이 문제 때문에 버그를 찾기 위해 거의 한 시간을 보냈습니다 ...
Matheus Weber

13

Swift 4에서

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

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 차원 배열에 적용됩니다. 이 방법을 사용하여 임의의 차원에서 배열을 만들 수 있습니다.
Duncan C

1
@vacawama, 멋지다. 단, n 차원 배열은를 사용하여 배열을 채우는 모든 솔루션과 동일한 문제를 가지고 Array(repeating:count:)있습니다. 다른 답변에 게시 한 댓글을 참조하십시오.
Duncan 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

이것은 하나의 간단한 라인으로 수행 할 수 있습니다.

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