앞으로 시간이 생길 때마다 Swift 알고리즘 클럽 내용을 공부해 보자😋 우선 쉬운 자료구조부터 살펴보자. Array2D!
우선 실습을 위해서 테스트 환경을 구성하자~
$ mkdir array2d
$ cd array2d
$ swift package init
C와 Objective-C 에서 2차원 배열 선언은 아래와 같다.
int cookies[9][7];
원소 접근은 인덱스를 사용한다.
int myCookie = cookies[3][6]
Swift는 위처럼 선언할 수 없다. Swift의 2차원 배열 선언 및 초기화는 좀 장황하다.
var cookies = [[Int]]()
for _ in 1...9 {
var row = [Int]()
for _ in 1...7 {
row.append(0)
}
cookies.append(row)
}
위처럼 초기화한 배열에 인덱스를 사용해 접근할 수 있다.
let myCookie = cookies[3][6]
XCTAssertEqual(myCookie, 0)
물론 한 줄로 2차원 배열을 선언할 수 있다.
let cookies = [[Int]](repeating: [Int](repeating: 0, count: 7), count: 9)
let myCookie = cookies[3][6]
XCTAssertEqual(myCookie, 0)
그래도 C언어만큼 쉬워 보이진 않는다.
축약할 수 있는 함수를 정의해 2차원 배열 선언을 좀 더 쉽게 할 수 있다.
func dim<T>(_ count: Int, _ value: T) -> [T] {
return [T](repeating: value, count: count)
}
let cookies = dim(9, dim(7, 0))
let myCookie = cookies[3][6]
XCTAssertEqual(myCookie, 0)
dim 함수를 사용하면 2차원 보다 높은 고차원 배열을 쉽게 만들 수 있다.
let threeDimensions = dim(2, dim(3, dim(4, 0)))
let element = threeDimensions[1][1][1]
XCTAssertEqual(element, 0)
dim 함수 대신에 좀 더 명확한 Array2D 데이터 타입을 만들어 보자.
public struct Array2D<T> {
public let columns: Int
public let rows: Int
fileprivate var array: [T]
public init(columns: Int, rows: Int, initialValue: T) {
self.columns = columns
self.rows = rows
array = .init(repeating: initialValue, count: rows * columns)
}
public subscript(column: Int, row: Int) -> T {
get {
precondition(0 <= column && column < columns, "Column \(column) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
precondition(0 <= row && row < rows, "Row \(row) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
return array[row * columns + column]
}
set {
precondition(0 <= column && column < columns, "Column \(column) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
precondition(0 <= row && row < rows, "Row \(row) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
array[row * columns + column] = newValue
}
}
}
1차원 배열을 사용하여 2차원 배열을 간단하게 정의해 보았다. 그리고 subscript
메서드를 구현했기 때문에 인덱스로 원소에 접근 가능하다.
var cookies = Array2D(columns: 9, rows: 7, initialValue: 0)
XCTAssertEqual(cookies.columns, 9)
XCTAssertEqual(cookies.rows, 9)
var myCookie = cookies[3, 6]
XCTAssertEqual(myCookie, 0)
cookies[3, 6] = 10
myCookie = cookies[3, 6]
XCTAssertEqual(myCookie, 10)
위 코드에서 precondition은 assert
와 비슷한 구문으로 조건이 false가 되면 프로그램은 실행을 멈추고 뒤의 메시지를 출력한다.