Swift 뿌수기 - Collection Types: Array

Wonbi·2022년 8월 17일
2

Swift 뿌수기

목록 보기
3/12

✅학습 내용

💎 Collection Types

✏️ Collection Types 이란?

Swift provides three primary collection types, known as arrays, sets, and dictionaries, for storing collections of values. Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.

  • Swift는 여러 값들을 저장하기 위해 Array, Set, Dictionary라는 collection type(컬렉션 타입)을 제공합니다. Array(배열)는 순서를 가진 값들의 컬랙션이고, Set(집합)는 순서가 없는 값들의 컬랙션입니다. Dictonary는 순서가 없는 key-value조합의 컬랙션입니다.
    Collection Types
  • 스위프트의 Array, Set, Dictionary는 저장되는 값과 키의 타입이 항상 명확해야 한다. 즉, 명시한 타입과 다른 잘못된 타입의 값을 실수로 삽입할 수 없다.

✏️ 컬렉션의 변동성

  • 만약 Array, Set, Dictionary를 만들고 변수로 할당하면, 해당 컬렉션은 변경가능 mutable 한 상태로 만들어진다. 생성한 이후 컬렉션의 항목을 추가, 제거, 변경 할 수 있다. 반대로 상수로 할당하면, 해당 컬렉션은 변경 불가immutable 한 상태로 만들어진다.

  • 변경할 필요가 없는 컬렉션은 상수로 할당하는 것이 좋다. 이렇게 하면 코드를 쉽게 추론할 수 있고, Swift 컴파일러가 컬렉션의 성능을 최적화할 수 있다.

💎 1. Array

An array stores values of the same type in an ordered list. The same value can appear in an array multiple times at different positions.

  • Array는 같은 타입의 값을 순서가 있는 목록의 형태로 저장합니다. 중복된 값이 배열 안에 서로 다른 위치에서 여러번 나타날 수 있습니다.

    Swift 의 ArrayNSArray와 호환이 가능합니다.

✏️ Array타입의 단축구문

  • Swift의 배열 타입은 Array<Element>로 작성된다. Element는 배열이 저장할 수 있는 값의 타입이다. [Element]라고 약식으로 작성될 수 있다. 두 가지 방법은 기능적으로 동일하지만, 배열 타입을 참조할 때 약식 형식이 더 선호된다.

✏️ 빈 배열 생성하기

  • 이니셜라이저를 이용하여 특정 타입의 빈 배열을 생성할 수 있다.
var someInts: [Int] = []
print("someInts는 항목이 \(someInts.count)개인 [Int] 유형입니다.")
// Prints "someInts는 항목이 0개인 [Int] 유형입니다."
  • someInts 변수의 타입은 이니셜라이저의 타입에서 [Int]로 추론된다.

  • 대안으로, 함수의 전달인자나 이미 타입이 지정된 변수 혹은 상수가 타입 정보를 이미 제공하는 경우, 빈 배열 리터럴[]을 사용하여 빈 배열을 만들 수 있다.

someInts.append(3)
// someInts에는 이제 Int 타입의 값이 1개 포함되어 있습니다.
someInts = []
// someInts는 이제 빈 배열이지만, 여전히 [Int]타입입니다.

✏️ 초기값을 가지는 배열 생성하기

  • Swift의 배열 타입은 모든 값이 동일한 기본값으로 설정된 특정 크기의 배열을 생성하기 위한 이니셜라이저를 제공한다. 이 이니셜라이저는 적절한 타입의 초기값(repeating)과, 해당 값이 새 배열에서 반복되는 횟수(count)를 전달한다.
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles는 [Double]타입이며, [0.0, 0.0, 0.0]과 습니다.

✏️ 두 배열을 더해서 생성하기

  • 덧셈 연산자+와 호환 가능한 타입인 두 기존 배열을 더함으로써 새로운 배열을 생성할 수 있다. 새 배열의 타입은 서로 더한 두 배열의 타입으로 추론한다.
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles는 [Double]타입이고, [2.5, 2.5, 2.5]과 같습니다.

var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles는 [Double]타입이라고 추론하며, [0.0, 0,0, 0.0, 2.5, 2.5, 2.5]과 같습니다.

✏️ 배열 리터럴로 배열 생성하기

  • 하나 이상의 값을 배열 컬렉션으로 짧게 줄여 작성하는 방식의 배열 리터럴로도 배열을 생성할 수 있다. 배열 리터럴은 쉼표로 구분되며 대괄호 쌍으로 둘러싸서 작성한다.

[value 1, value 2, value 3]

  • 다음 예제는 String값을 저장하는 shoppingList배열을 생성한다.
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList를 두 개의 초기값으로 초기화합니다.
  • shoppingList변수는 [String]으로 작성된 "문자열 값 배열"로 선언한다. 이 특정 배열은 String타입의 값을 지정했으므로, String값만 저장할 수 있다. 여기서 shoppingList배열은 배열 리터럴 내에 쓰여진 두 개의 문자열 값("Eggs""Milk")으로 초기화된다.

    shoppingList배열을 let을 쓴 상수가 아니라 var를 쓴 변수로 선언했는데, 이는 아래 예제에서 shoppingList 에 더 많은 항목을 추가하기 때문입니다.

  • 이 경우, 배열 리터럴은 두 String값 외에 다른 값은 포함되지 않는다. 이는 shoppingList변수 선언의 타입[String](String 값만 담을 수 있는 배열)과 일치하므로 두 개의 초기값으로 shoppingList를 초기화 하는 방법으로 배열 리터럴 할당을 허용한다.
  • Swift의 타입 추론 덕분에 동일한 타입의 값이 포함된 배열 리터럴로 초기화할 경우 배열 타입을 작성하지 않아도 된다.
var shoppingList = ["Eggs", "Milk"]
  • 배열 리터럴의 모든 값이 똑같은 타입이기 때문에, shoppingList변수에 사용할 올바른 타입이 [String]임을 스위프트가 추론할 수 있다.

✏️ 배열 접근 및 수정하기

  • 배열의 메소드 및 프로퍼티를 사용하거나, 첨자 구문(subscript syntax)을 사용하여 배열에 접근하고 수정할 수 있다.
  1. count
  • 배열의 항목 갯수를 확인하려면 읽기-전용(read-only) 프로퍼티 count를 사용하면 된다.
print("쇼핑 목록에는 (shoppingList.count)개의 항목이 포함되어 있습니다.")
// "쇼핑 목록에는 2개의 항목이 포함되어 있습니다." 를 인쇄함
  1. isEmpty
  • count프로퍼티 값이 0인지 확인하는 방법은 불리언 속성인 isEmpty프로퍼티 를 사용하는 것이다.
    - 스위프트는 컬렉션 타입이 비어있는지 검사할 때 isEmpty를 사용하라고 한다. 이는 단순히 편리하기 때문이 아니라 countIsEmpty의 사용 목적이 다르기 때문이다. 더 자세한 사항은 isEmpty vs. count == 0 다음 항목을 확인해보면 좋을 것이다.
  1. append(_:)
  • 배열의 append(_:)메소드를 호출하면 배열 끝에 새로운 항목을 덕붙일 수 있다.
shoppingList.append("Flour")
// shoppingList 는 이제 3 개의 항목을 담고 있으며, 누군가 팬케이크를 만드는가 봅니다.
  • 또는, "덧셈 할당 연산자+="를 사용하여 호환되는 하나 이상의 항목으로 된 배열을 덧붙일 수 있다.
shoppingList += ["Baking Powder"]
// shoppingList 는 이제 4개의 항목을 담고 있음
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 는 이제 7개의 항목을 담고 있음
  1. Array[index]
  • 첨자 구문을 사용해 배열 이름 바로 뒤에 있는 대괄호 안에 가져오려는 값의 '색인 (index)'을 전달하여 배열에 있는 값을 가져올 수 있다.
var firstItem = shoppingList[0]
// firstItem 은 "Eggs" 와 같음

배열의 첫번째 항목은 1이 아닌, 0입니다. 스위프트의 배열은 항상 0기반-색인(zero-indexed)입니다.

  • 첨자 구문을 사용하여 지정된 색인에 있는 기존 값을 변경할 수 있다.
shoppingList[0] = "Six eggs"
// 목록의 첫 번째 항목은 이제 "Eggs" 가 아닌 "Six eggs" 와 같음
  • 첨자 구문을 사용할 때는 지정한 색인이 유효해야 한다. 예를 들어, 배열 끝에 항목을 추가하고자 shoppingList[shoppingList.count] = "Salt"와 같이 작성 후 실행하면 런타임 오류가 발생한다.

    shippingList.count는 현재 배열에 있는 전체 항목의 개수를 나타내는데, 이 값으로 새 항목을 추가하면 그 행위 자체가 다시 count값을 바꾸게 됩니다. 이는 count라는 변수에 값을 읽는 행위와 값을 쓰는 행위를 동시에 하려는 문제가 발생합니다. 따라서 shippingList.count는 유효한 색인이 아닙니다.

  • 또한 첨자 구문을 사용하면, 교체할 값의 집합과 교체하려는 대상의 범위가 다르더라도 일정 값의 범위를 한번에 교체할 수 있다. 다음 예제는 "Chocolate Spread", "Cheese", 및 "Butter""Bananas""Apples" 로 교체한다.
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 는 이제 6 개의 항목을 담고 있음
  1. insert(_:at:)
  • 지정된 색인의 배열에 항목을 삽입하려면 배열의 insert(_:at:)메소드를 사용하면 된다.
shoppingList.insert("Maple Syrup", at: 0)
// shoppingList 는 이제 7 개의 항목을 담고 있음
// "Maple Syrup" 이 이제 목록의 첫 번째 항목임
  • insert(_:at:)메소드 호출은 '쇼핑목록'의 맨 앞에 색인을 '0'으로 표시한 "Maple Syrup"이라는 값을 가진 새 항목을 삽입한다.
  1. remove(at:)
  • insert(_:at:)메소드와 비슷하게 배열에 있는 항목은 remove(at:)메소드로 제거한다.
  • 또한 이 메소드는 지정된 색인에 있는 항목을 제거하고, 제거한 항목을 반환한다. (반환된 값이 필요하지 않으면 무시할 수 있다.)
let mapleSyrup = shoppingList.remove(at: 0)
// 방금 색인 0 에 있는 값을 제거함
// shoppingList 는 이제 6 개의 항목을 담으며, Maple Syrup 은 없음
// mapleSyrup 상수는 이제 제거한 문자열인 "Maple Syrup" 과 같음

배열에 존재하는 경계 밖의 색인으로 값에 접근하거나 수정하려고 하면, 런타임 에러가 발생할 것입니다. 색인을 사용하기 전에 이를 배열의 count 속성과 비교함으로써 유효한 지 검사할 수 있습니다. 배열 색인은 ‘0에서 시작’ 하기 때문에 ‘배열에서 가장 큰 유효 색인은 count - 1’ 입니다. 하지만, count 가 (빈 배열을 의미하는) 0 일 땐, 유효 색인이 아무 것도 없습니다.

  • 항목이 제거될 때 배열의 모든 빈틈이 메워지므로, 색인 0의 값은 다시 한번 "Six eggs"가 된다.
firstItem = shoppingList[0]
// firstItem 은 이제 "Six eggs" 임
  1. removeLast()
  • 배열의 제일 마지막 항목을 제거하고자 하면, 배열의 count프로퍼티를 조회하는 것을 피하도록 remove(at:)메소드 보다 removeLast()메소드를 사용한다.
  • remove(at:)메소드와 마찬가지로 removeLast()메소드는 제거된 항목울 반환한다.
let apples = shoppingList.removeLast()
// 방금 배열의 마지막 항목을 제거함
// shoppingList 는 이제 5 개의 항목을 담으며, apple 은 없음
// apples 상수는 이제 제거한 문자열인 "Apples" 와 같음

✏️ 배열에서 동작을 반복하기

  • for-in반복문으로 배열 전체의 값 집합에 대해 동작을 반복할 수 있다.

    ‘동작을 반복한다 (iterate over)’ 는 것은 ‘배열의 모든 항목마다 한 번씩 동작한다’ 는 의미입니다.

for item in shoppingList {
  print(item)
}

// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
  • 각 항목의 값 뿐 아니라 정수 색인이 필요할 경우 enumerated()메소드를 사용하면 된다. enumerated()메소드는 배열의 각 항목에 대해 정수와 항목으로 구성된 튜플을 반환한다. 정수는 0에서 시작하여 각 항목에 대해 1씩 카운트되며, 배열 전체를 열거(enumerate)하는 경우 이 정수들는 항목의 색인들과 일치한다. 매 반복 동작마다 이 튜플을 임시 상수나 변수로 분해할 수 있다.
for (index, value) in shoppingList.enumerated() {
  print("Item \(index + 1): \(value)")
}

// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas

1개의 댓글

comment-user-thumbnail
2022년 9월 1일

고수신가요?

답글 달기