배열은 Swift의 세 가지 주요 컬렉션 타입 중 하나예요. 배열은 원소를 순서대로 나열한 목록이에요. 배열은 어떤 타입의 원소든 저장할 수 있지만, 한 배열 안의 모든 원소는 같은 타입이어야 해요. 배열을 변수에 할당하면 변경할 수 있어요. 즉, 배열을 만든 뒤에도 원소를 추가하거나 제거하거나 수정할 수 있어요. 상수에 할당하면 배열은 변경할 수 없어요. 즉, 내용을 바꿀 수 없어요.
배열 리터럴은 대괄호([...])로 감싼, 쉼표로 구분된 원소 목록으로 작성해요.
Swift는 리터럴 안의 원소로부터 배열의 타입을 추론할 수 있어요.
let evenInts = [2, 4, 6, 8, 10, 12]
var oddInts = [1, 3, 5, 7, 9, 11, 13]
let greetings = ["Hello!", "Hi!", "¡Hola!"]
타입을 직접 지정할 수도 있어요.
배열 타입은 두 가지 방식으로 작성할 수 있어요. Array<T> 또는 축약 문법 [T]이고, 여기서 T는 배열이 담는 값의 타입이에요.
let evenInts: Array<Int> = [2, 4, 6, 8, 10, 12]
var oddInts: [Int] = [1, 3, 5, 7, 9, 11, 13]
let greetings: [String] = ["Hello!", "Hi!", "¡Hola!"]
count 속성을 사용하면 배열의 원소 개수를 알 수 있어요.
evenInts.count
// returns 6
빈 배열을 만들려면 타입을 지정해야 해요. 배열 초기화 구문이나 명시적 타입 주석을 사용하면 된답니다.
let emptyArray = [Int]()
let emptyArray2 = Array<Int>()
let emptyArray3: [Int] = []
배열을 중첩하면 다차원 배열을 만들 수 있어요.
중첩된 배열의 타입을 명시적으로 지정할 때는 [[Int]]나 Array<Array<Int>>처럼 원소 타입을 중첩된 대괄호로 감싸요.
let multiDimArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let multiDimArray2: [[Int]] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
append(_:) 메서드를 사용하면 변경 가능한 배열의 끝에 원소를 추가할 수 있어요.
var oddInts = [1, 3, 5, 7, 9, 11, 13]
oddInts.append(15)
// oddInts is now [1, 3, 5, 7, 9, 11, 13, 15]
insert(_:at:) 메서드를 사용하면 특정 인덱스에 원소를 삽입할 수 있어요.
이 메서드는 두 개의 인자를 받아요. 삽입할 원소와 삽입할 인덱스예요.
var oddInts = [1, 3, 5, 7, 9, 11, 13]
oddInts.insert(0, at: 0)
// oddInts is now [0, 1, 3, 5, 7, 9, 11, 13]
+ 연산자를 사용하면 두 배열을 하나의 배열로 합칠 수 있어요.
+ 연산자는 새로운 배열을 만들어 반환해요. 원래 배열은 수정하지 않아요.
var oddInts = [1, 3, 5, 7, 9, 11, 13]
let combined = oddInts + [15, 17, 19]
// combined is [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
print(oddInts)
// prints [1, 3, 5, 7, 9, 11, 13]
배열 이름 뒤에 대괄호([])로 인덱스를 넣으면 배열의 개별 원소에 접근할 수 있어요.
배열 인덱스는 0부터 시작하는 Int 값이고, 첫 번째 원소가 0이에요.
유효 범위를 벗어난 인덱스에 접근하면 런타임 오류가 발생하고 프로그램이 충돌해요.
let evenInts = [2, 4, 6, 8, 10, 12]
let oddInts = [1, 3, 5, 7, 9, 11, 13]
evenInts[2]
// returns 6
oddInts[7]
// Fatal error: Index out of range
변경 가능한 배열의 원소는 특정 인덱스에 새 값을 할당해서 바꿀 수 있어요. 원소를 읽을 때와 마찬가지로, 유효 범위를 벗어난 인덱스를 사용하면 런타임 오류가 발생해요.
var evenInts = [2, 4, 6, 8, 10, 12]
evenInts[2] = 0
// evenInts is now [2, 4, 0, 8, 10, 12]
joined(separator:) 메서드를 사용하면 문자열 배열을 하나의 문자열로 합칠 수 있어요. 이 메서드는 구분자 문자열을 받아요.
let evenInts = ["2", "4", "6", "8", "10", "12"]
let evenIntsString = evenInts.joined(separator: ", ")
// returns "2, 4, 6, 8, 10, 12"
split(separator:) 메서드에 구분 문자를 전달하면 문자열을 부분 문자열의 배열로 나눌 수 있어요.
let evenIntsString = "2, 4, 6, 8, 10, 12"
let evenInts = evenIntsString.split(separator: ",")
// returns ["2", " 4", " 6", " 8", " 10", " 12"]
remove(at:) 메서드를 사용하면 주어진 인덱스의 원소를 제거할 수 있어요.
인덱스는 배열의 유효 범위 안에 있어야 해요. 그렇지 않으면 런타임 오류가 발생해요.
var oddInts = [1, 3, 5, 7, 9, 11, 13]
oddInts.remove(at: 3)
// oddInts is now [1, 3, 5, 9, 11, 13]
배열의 마지막 원소를 제거하려면 removeLast() 메서드를 사용해요.
빈 배열에 removeLast()를 호출하면 런타임 오류가 발생해요.
var oddInts = [1, 3, 5, 7, 9, 11, 13]
oddInts.removeLast()
// oddInts is now [1, 3, 5, 7, 9, 11]
예비 마술사인 Elyse는 기초를 좀 연습해야 해요. Elyse에게는 조작하고 싶은 카드 스택이 있어요.
조금 더 쉽게 하기 위해 Elyse는 1부터 10까지의 카드만 사용해서, 카드 스택을 숫자 배열로 나타낼 수 있어요. 특정 카드의 위치는 배열의 인덱스에 대응해요. 즉, 위치 0은 첫 번째 카드, 위치 1은 두 번째 카드를 가리켜요.
모든 함수는 카드 배열을 수정한 다음, 수정된 배열을 반환해야 해요. 이는 Builder pattern이라고 알려진 흔한 작업 방식으로, 함수들을 멋지게 연결할 수 있게 해줘요.
카드를 고르려면, 주어진 스택에서 인덱스 position에 있는 카드를 반환해요.
두 개의 인자를 받는 getCard(at:from:) 함수를 구현해요. at은 스택에서 카드의 위치이고, from은 카드 스택이에요.
이 함수는 주어진 스택에서 위치 index에 있는 카드를 반환해야 해요.
let index = 2
getCard(at: index, from: [1, 2, 4, 1])
// returns 4
손재주를 좀 부려서, 인덱스 position에 있는 카드를 주어진 교체 카드와 바꿔요.
세 개의 인자를 받는 setCard(at:in:to) 함수를 구현해요. at은 스택에서 카드의 위치, in은 카드 스택, to는 위치 index에 있는 카드를 대체할 새 카드예요.
이 함수는 위치 index에 있는 카드가 새 카드로 바뀐 스택의 복사본을 반환해야 해요.
주어진 index가 스택에서 유효한 인덱스가 아니면, 원래 스택을 변경 없이 그대로 반환해야 해요.
let index = 2
let newCard = 6
setCard(at: index, in: [1, 2, 4, 1], to: newCard)
// returns [1, 2, 6, 1]
스택 맨 위에 새 카드를 넣어서 카드가 나타나게 해요.
두 개의 인자를 받는 insert(_:atTopOf:) 함수를 구현해요. 인자는 삽입할 새 카드와 카드 스택이에요.
이 함수는 주어진 새 카드가 스택 맨 위에 추가된 스택의 복사본을 반환해야 해요.
let newCard = 8
insert(newCard, atTopOf: [5, 9, 7, 1])
// returns [5, 9, 7, 1, 8]
스택에서 주어진 position에 있는 카드를 제거해서 카드가 사라지게 해요.
두 개의 인자를 받는 removeCard(at:from:) 함수를 구현해요. at은 스택에서 카드의 위치이고, from은 카드 스택이에요.
이 함수는 위치 index에 있는 카드가 제거된 스택의 복사본을 반환해야 해요.
주어진 index가 스택에서 유효한 인덱스가 아니면, 원래 스택을 변경 없이 그대로 반환해야 해요.
let index = 2
removeCard(at: index, from: [3, 2, 6, 4, 8])
// returns [3, 2, 4, 8]
스택의 주어진 position에 새 카드를 넣어서 카드가 나타나게 해요.
세 개의 인자를 받는 insert(_:at:from:) 함수를 구현해요. 인자는 삽입할 새 카드, 새 카드를 삽입할 위치, 카드 스택이에요.
이 함수는 주어진 새 카드가 주어진 위치에 추가된 스택의 복사본을 반환해야 해요.
주어진 index가 스택에서 유효한 인덱스가 아니면, 원래 스택을 변경 없이 그대로 반환해야 해요.
let newCard = 8
insert(newCard, at: 2, from: [5, 9, 7, 1])
// returns [5, 9, 8, 7, 1]
스택의 크기가 stackSize와 같은지 아닌지 확인해요.
두 개의 인자를 받는 checkSizeOfStack(_:_:) 함수를 구현해요. stack은 카드 스택이고, stackSize는 스택의 크기예요.
이 함수는 스택의 크기가 stackSize와 같으면 true를, 그렇지 않으면 false를 반환해야 해요.
let stackSize = 4
checkSizeOfStack([3, 2, 6, 4, 8], stackSize)
// returns false
Exercism에 가입하고 Swift 트랙을 개념 35개연습 문제 116개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.