λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🍎 iOS/Swift

[Swift] Collection Type - λ°°μ—΄ (Array), ArraySlice, CoW

by Danna 2021. 5. 28.
728x90
728x90

μ•ˆλ…•ν•˜μ„Έμš”! 이번 ν¬μŠ€νŒ…μ€ Swift 데이터ꡬ쑰와 μ•Œκ³ λ¦¬μ¦˜ μ±…μ˜ 2μž₯ μŠ€ν„°λ”” 쀑 λ‘λ²ˆμ§Έ 핡심 λ‚΄μš©μΈ Collection Type 에 λŒ€ν•œ λ‚΄μš©μž…λ‹ˆλ‹€. Array (λ°°μ—΄), Dictionary (λ”•μ…”λ„ˆλ¦¬, μ‚¬μ „ν˜•), Set (μ„ΈνŠΈ), Tuple(νŠœν”Œ) 넀가지 νƒ€μž…μ— λŒ€ν•΄ ν•™μŠ΅ν–ˆμŠ΅λ‹ˆλ‹€.

 

πŸ‘€ μ»¬λ ‰μ…˜ νƒ€μž…(Collection Type)

μ»¬λ ‰μ…˜ νƒ€μž…μ€ μ—¬λŸ¬ 값을 μ €μž₯ν•  수 μžˆλŠ” ν˜•νƒœλ‘œ, Swift 에 κ΅¬ν˜„λœ μ»¬λ ‰μ…˜ νƒ€μž…μ€ Array, Dictionary, Set κ°€ μžˆμŠ΅λ‹ˆλ‹€. Tuple 은 μ»¬λ ‰μ…˜ νƒ€μž…μ€ μ•„λ‹ˆμ§€λ§Œ, μœ μ‚¬ν•œ λ°©μ‹μœΌλ‘œ ν™œμš©λ©λ‹ˆλ‹€!

 

  • λ°°μ—΄(Array) : μˆœμ„œλ₯Ό 가지며, 동일 νƒ€μž…μ˜ 값을 λͺ©λ‘μœΌλ‘œ μ €μž₯ν•˜λŠ” μ»¬λ ‰μ…˜
  • λ”•μ…”λ„ˆλ¦¬(Dictionary; μ‚¬μ „ν˜•) : λ™μΌν•œ 데이터 νƒ€μž…μ΄ Key: Value 쌍으둜 묢인 μˆœμ„œκ°€ μ—†λŠ” μ»¬λ ‰μ…˜, 사전과 λΉ„μŠ·ν•œ ꡬ쑰
  • μ„ΈνŠΈ(Set) : nil 이 ν¬ν•¨λ˜μ§€ μ•Šκ³  μ„œλ‘œ μ€‘λ³΅λ˜μ§€ μ•ŠλŠ” κ°’μœΌλ‘œ κ΅¬μ„±λœ μˆœμ„œκ°€ μ—†λŠ” μ»¬λ ‰μ…˜, μˆ˜ν•™μ—μ„œμ˜ 집합 κ°œλ…μ„ 기반으둜 λ§Œλ“  νƒ€μž…
  • νŠœν”Œ(Tuple) : λ‹€μ–‘ν•œ 데이터 νƒ€μž…μ˜ 값을 담을 수 μžˆλŠ” νƒ€μž…(λ‚΄λΆ€ μš”μ†Œκ°€ λͺ¨λ“  같은 νƒ€μž…μ΄ μ•„λ‹ˆμ–΄λ„ 됨), μ—°κ΄€ κ°’μ˜ μž„μ‹œ 그룹을 λ§Œλ“œλŠ”λ° μ‚¬μš© (ν•¨μˆ˜μΈμž, λ°˜ν™˜κ°’ λ“±)

✏️ λ°°μ—΄(Array)

λ°°μ—΄(Array) λŠ” μˆœμ„œλ₯Ό 가지며, 동일 νƒ€μž…μ˜ 값을 λͺ©λ‘μœΌλ‘œ μ €μž₯ν•˜λŠ” 데이터 νƒ€μž…μž…λ‹ˆλ‹€. Swift μ—μ„œ 배열에 μ €μž₯ν•˜λŠ” 값은 Generic type collections 으둜 int, float, string, μ—΄κ±°ν˜•(enumerate), ν΄λž˜μŠ€κΉŒμ§€ μ–΄λ–€ νƒ€μž…μ΄λ“  κ°€λŠ₯ν•©λ‹ˆλ‹€.

 

βœ”οΈŽ λ°°μ—΄ μ΄ˆκΈ°ν™”

Swift ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 넀가지 μ΄ˆκΈ°ν™” λ©”μ†Œλ“œλ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

μ €λŠ” μ„Έλ²ˆμ§Έ 방식인 λ°°μ—΄μ˜ 값을 지정해 μ„ μ–Έν•˜λŠ” 방식을 자주 μ‚¬μš©ν•΄μš”. ν˜Ήμ€ μ΄ˆκΈ°κ°’ 지정이 ν•„μš”ν•œ 경우 4번째 방식을 μ΄μš©ν•©λ‹ˆλ‹€!

 

// 1 정식 문법
var intArray = Array<Int>()

// 2 단좕 ν‘œν˜„ 문법
intArray = [Int]()

// 3 λ°°μ—΄μ˜ 값을 μ§€μ •ν•΄μ„œ μ„ μ–Έν•˜λŠ” 방식
var intLiteralArray: [Int] = [1, 2, 3]

// 3-1 μœ„μ˜ 단좕 ν‘œν˜„ 방식 (νƒ€μž…μ€ Int둜 μΆ”μ •λœλ‹€)
intLiteralArray = [1, 2, 3]

// 4 ν•˜λ‚˜μ˜ νŠΉμ • κ°’μœΌλ‘œ λ°°μ—΄ μƒμ„±ν•˜κΈ° [2, 2, 2, 2, 2]
intLiteralArray = [Int](repeating:2, count: 5)

 

βœ”οΈŽ λ°°μ—΄ μš”μ†Œ μΆ”κ°€ 및 μ—…λ°μ΄νŠΈ

  • append(_:) λ©”μ†Œλ“œ
    λ°°μ—΄μ˜ 맨 λ§ˆμ§€λ§‰ 뢀뢄에 μƒˆλ‘œμš΄ μš”μ†Œλ₯Ό μΆ”κ°€ν•œλ‹€. μ‹œκ°„λ³΅μž‘λ„ O(1)
  • append(contentsOf:) λ©”μ†Œλ“œ
    λ°°μ—΄μ˜ 맨 λ§ˆμ§€λ§‰ 뢀뢄에 μ‹œν€€μŠ€μ˜ μš”μ†Œλ“€μ„ μΆ”κ°€ν•œλ‹€. μ‹œκ°„λ³΅μž‘λ„ 평균 O(m), m 은 μΆ”κ°€λ˜λŠ” μ‹œν€€μŠ€μ˜ 길이
  • insert(_: at:) λ©”μ†Œλ“œ
    λ°°μ—΄μ˜ νŠΉμ • μΈλ±μŠ€μ— μƒˆλ‘œμš΄ μš”μ†Œλ₯Ό μΆ”κ°€ν•œλ‹€.
    μ‹œκ°„λ³΅μž‘λ„ O(n), n 은 λ°°μ—΄μ˜ 길이. λ§ˆμ§€λ§‰ 인덱슀인 경우, append λ©”μ†Œλ“œμ™€ κ°™μ•„μ§€λ―€λ‘œ O(1)
  • insert(contentsOf: at:) λ©”μ†Œλ“œ
    λ°°μ—΄μ˜ νŠΉμ • μΈλ±μŠ€μ— μ‹œν€€μŠ€μ˜ μš”μ†Œλ“€μ„ μΆ”κ°€ν•œλ‹€.
    μ‹œκ°„λ³΅μž‘λ„ O(n + m), n은 κΈ°μ‘΄ λ°°μ—΄μ˜ 길이, m 은 μΆ”κ°€λ˜λŠ” μ‹œν€€μŠ€μ˜ 길이.
    λ§ˆμ§€λ§‰ 인덱슀인 경우 append(contentsOf:) λ©”μ†Œλ“œμ™€ κ°™μ•„μ§€λ―€λ‘œ O(m).
  • λ°°μ—΄ μš”μ†Œ μ—…λ°μ΄νŠΈ array[i]
    λ°°μ—΄μ˜ νŠΉμ • 인덱슀의 μš”μ†Œ 값을 λ³€κ²½ν•  λ•Œμ—λŠ” μ„œλΈŒμŠ€ν¬λ¦½νŠΈ 문법을 μ‚¬μš©ν•΄μ„œ λ³€κ²½ν•  수 μžˆλ‹€.
// Declaration
mutating func append(_ newElement: Int)

mutating func append<S>(contentsOf newElements: S) where Element == S.Element, S : Sequence

mutating func insert(_ newElement: Int, at i: Int)

mutating func insert<C>(contentsOf newElements: C, at i: Int) where C : Collection, Self.Element == C.Element

// Example code
var intArray : [Int] = []
intArray.append(4) 
// [4]
intArray.append(contentsOf: [5, 6, 7])
// [4, 5, 6, 7]
intArray.insert(1, at: 0)
// [1, 4, 5, 6, 7]
intArray.insert(contentsOf: [2, 3], at: 1)
// [1, 2, 3, 4, 5, 6, 7]
intArray[0] = 0 
// [0, 2, 3, 4, 5, 6, 7]

 

βœ”οΈŽ λ°°μ—΄μ—μ„œ μ—¬λŸ¬ μš”μ†Œλ₯Ό κ°€μ Έμ˜€λŠ” 방법

  • μ„œλΈŒμŠ€ν¬λ¦½νŠΈμ™€ 인덱슀 λ²”μœ„λ₯Ό 톡해 값을 κ°€μ Έμ˜€κ±°λ‚˜ μ—…λ°μ΄νŠΈν•  수 μžˆλ‹€.
  • for ... in 문법을 톡해 λ°°μ—΄ μš”μ†Œλ₯Ό λ°˜λ³΅ν•  수 μžˆλ‹€.
  • for ... in 문법 μ‚¬μš©μ‹œ μΈλ±μŠ€μ™€ 값을 λ™μ‹œμ— μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” enumerate(array) ν•¨μˆ˜λ₯Ό μ΄μš©ν•  수 μžˆλ‹€.
// intArray = [0, 2, 3, 4, 5, 6, 7]
intArray[1...4] // [2, 3, 4, 5], 인덱슀 4 λ₯Ό ν¬ν•¨ν•œλ‹€.
intArray[1..<4] // [2, 3, 4], 인덱슀 4 λ₯Ό ν¬ν•¨ν•˜μ§€ μ•ŠλŠ”λ‹€.
intArray[0...2] = [10, 20, 30] // intArray = [10, 20, 30, 4, 5, 6, 7]

// λ°°μ—΄μ˜ λͺ¨λ“  μš”μ†Œλ₯Ό λ°˜λ³΅ν•œλ‹€
for element in intArray { 
     print(element) 
}

// λ°°μ—΄μ˜ μš”μ†Œλ₯Ό λ°˜λ³΅ν•˜λ©° 인덱슀λ₯Ό ν•¨κ»˜ μ‚¬μš©ν•  수 μžˆλ‹€
for (index, value) in enumerate(intArray) {
    print("intArray[\(index)]: \(value)")
}

 

βœ”οΈŽ λ°°μ—΄μ˜ 개수 확인, νŠΉμ • 값이 μžˆλŠ”μ§€ 확인, νŠΉμ • κ°’μ˜ 인덱슀λ₯Ό μ°ΎκΈ°

  • array.count 속성 :: λ°°μ—΄μ˜ 개수λ₯Ό ν™•μΈν•˜λŠ” 속성 (Int)
  • array.isEmpty 속성 :: 배열이 λΉ„μ—ˆλŠ”μ§€ ν™•μΈν•˜λŠ” 속성 (Bool)
  • array.contains(_:) λ©”μ†Œλ“œ :: νŠΉμ • 값이 μžˆλŠ”μ§€ 확인해 Bool 값을 λ°˜ν™˜.
  • array.firstIndex(of:) λ©”μ†Œλ“œ :: νŠΉμ • κ°’κ³Ό μΌμΉ˜ν•˜λŠ” 첫번째 인덱슀λ₯Ό λ°˜ν™˜, μ—†λŠ” 경우 nil
  • array.lastIndex(of:) λ©”μ†Œλ“œ :: νŠΉμ • κ°’κ³Ό μΌμΉ˜ν•˜λŠ” λ§ˆμ§€λ§‰ 인덱슀λ₯Ό λ°˜ν™˜, μ—†λŠ” 경우 nil
intArray.count // 7
intArray.isEmpty // false
intArray.contains(55) // false
intArray.firstIndex(of: 2) // 1
intArray.lastIndex(of: 2) // 1
intArray.firstIndex(of: 10) //nil

 

 

πŸ’‘ ArraySlice ?

배열을 μ„œλΈŒμŠ€ν¬λ¦½νŠΈ, 인덱슀 λ²”μœ„λ₯Ό 톡해 μƒˆλ‘œμš΄ λ²”μœ„μ˜ 배열을 μ§€μ •ν•œ 경우, μ΄λŠ” Array νƒ€μž…μ΄ μ•„λ‹Œ ArraySlice νƒ€μž…μ΄ λ©λ‹ˆλ‹€. ArraySlice λŠ” κΈ°μ‘΄ λ°°μ—΄μ˜ μ €μž₯μ†Œλ₯Ό μ°Έμ‘°ν•˜κ³ , Array κ°€ μ œκ³΅ν•˜λŠ” 속성과 λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (ArraySlice λŠ” 기본적으둜 writing ν•˜μ§€ μ•Šμ„ κ²ƒμ΄λΌλŠ” 가정을 ν•œλ‹€κ³  ν•©λ‹ˆλ‹€.) 

 

ArraySlice 의 원본 λ°°μ—΄μ˜ 라이프 사이클이 λλ‚˜λ©΄, ArraySlice 에 μ €μž₯된 λ°°μ—΄ μš”μ†Œλ“€λ„ μ ‘κ·Ό λΆˆκ°€λŠ₯ν•΄μ§‘λ‹ˆλ‹€. λ˜ν•œ, ArraySlice μΈμŠ€ν„΄μŠ€κ°€ μ‚΄μ•„μžˆλŠ” λ™μ•ˆ Array 에 λŒ€ν•œ μ°Έμ‘°κ°€ 계속 μœ μ§€λ˜λ―€λ‘œ, μ˜€λžœμ‹œκ°„λ™μ•ˆ μ‚¬μš©λ˜μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€κ³  ν•©λ‹ˆλ‹€. (라이프 사이클이 κΈ΄ ν΄λ‘œμ € λ“±μ—μ„œ ArraySlice λ₯Ό μ°Έμ‘°ν•˜μ§€ μ•Šλ„λ‘ ν•©λ‹ˆλ‹€.) 

 

ArraySlice μΈμŠ€ν„΄μŠ€μ˜ μ‹œμž‘ μΈλ±μŠ€λŠ” 항상 0 이 μ•„λ‹Œ 점이 μ€‘μš”ν•œλ°μš”, μ•„λž˜ μ½”λ“œμ—μ„œ subIntArray[0] 은 μ—λŸ¬κ°€ λ°œμƒν•©λ‹ˆλ‹€ πŸ‘€..! μ•ˆμ „ν•˜κ²Œ μ ‘κ·Όν•˜κΈ° μœ„ν•΄ startIndex, endIndex λ₯Ό ν™œμš©ν•©μ‹œλ‹€. subIntArray[2] 와 같이 μ ‘κ·Όν•  μˆ˜λ„ μžˆμ§€λ§Œ, 맀번 κ°„λ‹¨ν•œ λ°°μ—΄μ˜ 연산을 ν•˜λŠ”κ±΄ μ•„λ‹ˆλ‹ˆκΉμš”. 

var intArray: [Int] = [1, 2, 3, 4, 5]
var subIntArray = intArray[2...4] // [3, 4, 5]

print(type(of: intArray)) // Array<Int>
print(type(of: subIntArray)) // ArraySlice<Int>

//subIntArray[0] // Fatal error: Index out of bounds
subIntArray.startIndex // 2
subIntArray[subIntArray.startIndex] // 3
subIntArray[2] // 3

 

πŸ’‘ Copy-on-Write (CoW) ?

Copy-on-Write (CoW) λŠ” νŠΉμ • μΈμŠ€ν„΄μŠ€λ₯Ό λ³΅μ‚¬ν•œ 경우, μˆ˜μ •(Write)이 일어날 λ•Œ 볡사(Copy) ν•˜λŠ” κΈ°λ²•μž…λ‹ˆλ‹€. 

μŠ€μœ„ν”„νŠΈμ˜ Collection Type 인 Array, Dictionary, Set μ—μ„œ 원본 λ¦¬μ†ŒμŠ€λ₯Ό 볡사할 λ•Œ μ μš©λ©λ‹ˆλ‹€.

* μ‚¬μš©μž μ •μ˜ κ΅¬μ‘°μ²΄μ—μ„œλ„ CoW κ°œλ…μ„ μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (μ—¬κΈ° 링크λ₯Ό μ°Έκ³ ν•΄μ£Όμ„Έμš”)

 

μ •λ¦¬ν•˜μžλ©΄!

  • μ›λ³Έμ΄λ‚˜ 볡사본이 μˆ˜μ •λ˜κΈ° μ „κΉŒμ§€λŠ” 볡사λ₯Ό ν•˜μ§€ μ•Šκ³ , 원본 λ¦¬μ†ŒμŠ€λ₯Ό κ³΅μœ ν•œλ‹€.
  • μ›λ³Έμ΄λ‚˜ λ³΅μ‚¬λ³Έμ—μ„œ μˆ˜μ •μ΄ 일어날 경우, κ·Έ λ•Œ λ³΅μ‚¬ν•˜λŠ” μž‘μ—…μ„ ν•œλ‹€.
  • => μˆ˜μ •ν•˜μ§€ μ•ŠλŠ” κ²½μš°μ—λŠ” 원본 λ¦¬μ†ŒμŠ€λ₯Ό μ°Έμ‘°ν•˜μ—¬ λΆˆν•„μš”ν•œ λ©”λͺ¨λ¦¬ μ‚¬μš©κ³Ό μ‹œκ°„μ„ 쀄이기 μœ„ν•¨μ΄λ‹€.

 

Array μ—μ„œμ˜ CoW 예제

 

πŸ’‘ λ°°μ—΄ μš©λŸ‰ (Array's capacity) ?

λ°°μ—΄μ˜ instance λ₯Ό μƒμ„±ν•˜λ©΄ ν•΄λ‹Ή λ°°μ—΄ μš”μ†Œλ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•œ μΆ”κ°€ μ €μž₯ 곡간이 ν• λ‹Ήλ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ μΆ”κ°€ μ €μž₯ 곡간을 λ°°μ—΄ μš©λŸ‰(Array's capacity) 라고 ν•˜λ©°, 배열에 μ €μž₯된 μš”μ†Œμ˜ κ°œμˆ˜μ— 잠재적인 μ €μž₯ 곡간을 ν¬ν•¨ν•œ μš©λŸ‰μž…λ‹ˆλ‹€.

 

  • Array.count :: 배열에 μ €μž₯된 μš”μ†Œμ˜ 개수 
  • Array.capacity :: μƒˆ μ €μž₯μ†Œλ₯Ό ν• λ‹Ήν•˜μ§€ μ•Šκ³  배열에 μ €μž₯ν•  수 μžˆλŠ” μš”μ†Œμ˜ 개수 (잠재적인 μ €μž₯ 곡간을 포함)

배열에 λŒ€λŸ‰μ˜ μš”μ†Œκ°€ 좔가될 것을 미리 μ•Œκ³ μžˆλŠ” 경우, reserveCapacity(_ capacity:) λ©”μ†Œλ“œλ₯Ό 톡해 좔가적인 λ°°μ—΄ μš©λŸ‰μ„ 미리 ν• λ‹Ήν•  수 μžˆμŠ΅λ‹ˆλ‹€! μ €μž₯ 곡간을 미리 확보해두어, μƒˆλ‘œμš΄ μš”μ†Œκ°€ 좔가될 λ•Œλ§ˆλ‹€ 슀슀둜 μ €μž₯곡간을 ν• λ‹Ήν•˜λŠ”λ° λ“œλŠ” μ‹œκ°„μ„ 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€. 

var intArray = [Int]()
intArray.capacity // 0개 μš”μ†Œλ₯Ό 포함
intArray.reserveCapacity(500)
intArray.capacity // 508개 μš”μ†Œλ₯Ό 포함 (μ‹€ν–‰ μ„±λŠ₯을 κ³ λ €ν•΄ μ‹€μ œ μš”μ²­ν•œ μ–‘ μ΄μƒμœΌλ‘œ ν• λ‹Ή)

 

πŸ‘‰ λ”•μ…”λ„ˆλ¦¬(Dictionary) 

πŸ‘‰ μ„ΈνŠΈ(Set)

πŸ‘‰ νŠœν”Œ(Tuple)

 


참고 링크

728x90
728x90