Bibi's DevLog πŸ€“πŸŽ

[Swift 자료ꡬ쑰] 1. Array λ°°μ—΄ (생성, CRUD, COW) λ³Έλ¬Έ

ν”„λ‘œκ·Έλž˜λ°/Data Structures 자료ꡬ쑰

[Swift 자료ꡬ쑰] 1. Array λ°°μ—΄ (생성, CRUD, COW)

λΉ„λΉ„ bibi 2022. 12. 16. 12:37

Apple Developer Documentation

https://nitinagam17.medium.com/data-structure-in-swift-ios-part-1-305dd33e19f5

μœ„μ˜ 두 λ¬Έμ„œλ₯Ό 기반으둜 μ •λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

Array

λ°°μ—΄ : μˆœμ„œκ°€ 있고 μž„μ˜ 접근이 κ°€λŠ₯ν•œ μ»¬λ ‰μ…˜(κ°’μ˜ λͺ¨μŒ).

κ°€μž₯ ν”ν•˜κ²Œ μ“°λŠ” 데이터 νƒ€μž…μ΄λ‹€.

Array

An ordered, random-access collection.

@frozen struct Array<Element>
  • Array : 단일 νƒ€μž…μ˜ μš”μ†Œλ“€μ„ λ‹΄μŒ
  • Element : Array λ‚΄λΆ€μ˜ μš”μ†Œμ˜ νƒ€μž…

생성

let nameArray = ["Alex", "Martin", "Harry"]
let oddNumbers = [1, 3, 5, 7, 9, 11, 13, 15]

// Element νƒ€μž…μ„ μ„ μ–Έν•΄ 빈 배열을 λ§Œλ“€ 수 μžˆλ‹€
var emptyDoubles: [Double] = []
var emptyFloats: Array<Float> = Array()

var digitCounts = Array(repeating: 0, count: 10)
print(digitCounts) // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

λ°°μ—΄μ˜ 값에 μ ‘κ·Όν•˜κΈ°

let oddNumbers = [1, 3, 5, 7, 9, 11, 13, 15]

if oddNumbers.isEmpty {
    print("I don't know any odd numbers.")
} else {
    print("I know \(oddNumbers.count) odd numbers.")
}
// Prints "I know 8 odd numbers."

if let firstElement = oddNumbers.first, let lastElement = oddNumbers.last {
    print(firstElement, lastElement, separator: ", ")
}
// Prints "1, 15"

print(emptyDoubles.first, emptyDoubles.last, separator: ", ")
// Prints "nil, nil"

print(oddNumbers[0], oddNumbers[3], separator: ", ")
// Prints "1, 7"

print(emptyDoubles[0])
// Triggers runtime error: Index out of range
  • isEmpty : O(1)
  • count : O(1)
  • first
  • last : O(1)
  • λ“±λ“± λ‹€μ–‘ν•œ ν”„λ‘œνΌν‹°κ°€ μ‘΄μž¬ν•¨
  • μ„œλΈŒμŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•΄ μΈλ±μŠ€λ‘œλ„ μ ‘κ·Ό κ°€λŠ₯

λ°°μ—΄μ˜ νŠΉμ§•

for name in nameArray { // Sequence
        print(name)
}

let firstName = nameArray.[0]
let lastName = nameArray.last
  • μ œλ„€λ¦­μœΌλ‘œ κ΅¬ν˜„λœ μ»¬λ ‰μ…˜μž„
    • = μ–΄λ–€ νƒ€μž…μ˜ 데이터든 담을 수 μžˆλ‹€.
  • 배열은 Sequence μž„
    • λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•΄ 배열을 반볡(iterate)ν•  수 있음.
  • 배열은 μ»¬λ ‰μ…˜μž„
    • μš”μ†Œλ₯Ό μˆœνšŒν•  수 있음
    • μ„œλΈŒμŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•  수 있음. Array[index]
  • 배열은 RandomAccessCollection ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•¨
    • = νš¨μœ¨μ„±μ„ 보μž₯함
    • 예λ₯Ό λ“€μ–΄, λ°°μ—΄μ˜ 크기가 크든 μž‘λ“  Array.count ν”„λ‘œνΌν‹°μ˜ 값을 κ°€μ Έμ˜€λŠ” 데 λ™μΌν•œ μ‹œκ°„μ΄ κ±Έλ¦Ό.

λ°°μ—΄μ˜ λ©”μ„œλ“œ - μ‚½μž…, μ‚­μ œ, μˆ˜μ •, 탐색 (CRUD) λ“±λ“±

  • μ‚½μž… Insert
    • append(_:)
      • λ°°μ—΄μ˜ λ§ˆμ§€λ§‰μ— μš”μ†Œ μ‚½μž… : O(1) . κ°€μž₯ 효율적인 방법.
      • λ©”λͺ¨λ¦¬ μž¬ν• λ‹Ήμ΄ 일어날 λ•ŒλŠ” μ˜ˆμ™Έμ μœΌλ‘œ O(n) μ‹œκ°„μ΄ κ±Έλ¦°λ‹€.
    • append(contentsOf:)
      • λ°°μ—΄μ˜ λ§ˆμ§€λ§‰μ— λ°°μ—΄ μ‚½μž… : O(M) (M은 μƒˆλ‘œμš΄ Elements의 개수)
    • insert(_:at:)
      • λ°°μ—΄μ˜ νŠΉμ • μœ„μΉ˜μ— μš”μ†Œ μ‚½μž… : O(n)μ‹œκ°„μ΄ κ±Έλ¦°λ‹€.
  • μ‚­μ œ Remove
    • removeLast()
      • λ°°μ—΄μ˜ λ§ˆμ§€λ§‰ μš”μ†Œ μ‚­μ œ : O(1)
    • remove(at:)
      • λ°°μ—΄μ˜ νŠΉμ • μœ„μΉ˜μ˜ μš”μ†Œ μ‚­μ œ : O(n)
    • removeFirst()
      • λ°°μ—΄μ˜ 첫 μš”μ†Œ μ‚­μ œ : O(n)
  • μˆ˜μ • Update
    • 이미 μ‘΄μž¬ν•˜λŠ” μš”μ†Œμ— μƒˆ 값을 ν• λ‹Ήν•¨μœΌλ‘œμ„œ 값을 λ°”κΏ€ 수 μžˆλ‹€.
  • 탐색 Read / Search
    • μ„œλΈŒμŠ€ν¬λ¦½νŠΈ : O(1)
    • contains(_:) : O(n)
    • firstIndex(of:) , lastIndex(of:)
      • 첫 번쨰둜 λ‚˜νƒ€λ‚˜λŠ” / λ§ˆμ§€λ§‰μœΌλ‘œ λ‚˜νƒ€λ‚˜λŠ” μ›μ†Œμ˜ 인덱슀 μ°ΎκΈ° : O(n)
    • min(), max()
      • μ΅œμ†Œ/μ΅œλŒ“κ°’ μ°ΎκΈ° : O(n)
  • μ •λ ¬ Sort
    • sort(), sorted()
      • μ •λ ¬ν•˜κΈ° : O(N logN) . Tim Sort λΌλŠ” 방법 μ‚¬μš©.
  • split(separator:maxSplits:omittingEmptySubsequences:)
    • separator κΈ°μ€€μœΌλ‘œ λ‚˜λˆ„κΈ° - O(n)

λ°°μ—΄μ˜ 크기 늘리기

λͺ¨λ“  배열은 μš”μ†Œλ₯Ό λ‹΄κΈ° μœ„ν•΄ μΌμ •λŸ‰μ˜ λ©”λͺ¨λ¦¬λ₯Ό μ°¨μ§€ν•œλ‹€.

μš”μ†Œλ₯Ό μΆ”κ°€ν–ˆμ„ λ•Œ λ°°μ—΄μ˜ 크기가 λŠ˜μ–΄λ‚˜μ•Ό ν•œλ‹€λ©΄, κΈ°μ‘΄ λ°°μ—΄μ˜ 2배에 ν•΄λ‹Ήν•˜λŠ” μƒˆ λ©”λͺ¨λ¦¬ 곡간을 작고 κΈ°μ‘΄ 값을 볡사해 λ„£λŠ” μ‹μœΌλ‘œ 크기가 λŠ˜μ–΄λ‚œλ‹€. μ΄λŸ¬ν•œ μž¬ν• λ‹Ή(reallocation) μž‘μ—…μ€ μ„±λŠ₯ λΉ„μš©μ΄ μžˆμ§€λ§Œ, 배열이 컀짐에 따라 λ°œμƒ λΉˆλ„κ°€ 쀄어든닀.

λ§Œμ•½ 배열에 μ–Όλ§ˆλ‚˜ λ§Žμ€ μš”μ†Œλ“€μ„ μ €μž₯ν•˜κ²Œ 될지 λŒ€λž΅μ μœΌλ‘œ μ•Œκ³  μžˆλ‹€λ©΄, 배열에 값을 λ„£κΈ° 전에 reserveCapacity(_:) λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄ μž¬ν• λ‹Ήμ„ ν”Όν•  수 μžˆλ‹€. 또, capacity 와 count ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•΄ μž¬ν• λ‹Ή 없이 μ–Όλ§ˆλ‚˜ 더 λ§Žμ€ μš”μ†Œλ“€μ„ 배열에 μ €μž₯ν•  수 μžˆλŠ”μ§€ κ°€λŠ ν•  수 μžˆλ‹€.

λ°°μ—΄μ˜ 볡사값 μˆ˜μ •ν•˜κΈ°

각각의 배열은 μžμ‹ μ˜ μš”μ†Œλ“€μ„ λͺ¨λ‘ ν¬ν•¨ν•˜λŠ” 독립적인 값을 가진닀.

  • λ°°μ—΄μ˜ μš”μ†Œκ°€ κ°„λ‹¨ν•œ νƒ€μž…μ΄λ‚˜ ꡬ쑰체의 경우
    • 값을 ν†΅μ§Έλ‘œ λ³΅μ‚¬ν•˜λ―€λ‘œ, μ–΄λ–€ λ°°μ—΄μ˜ μˆ˜μ •λ‚΄μ—­μ΄ λ‹€λ₯Έ 배열에 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠλŠ”λ‹€.
    • Swift의 배열은 ꡬ쑰체이기 λ•Œλ¬Έμ—, λ‹€λ₯Έ μƒμˆ˜λ‚˜ λ³€μˆ˜μ— ν• λ‹Ήλ˜κ±°λ‚˜ ν•¨μˆ˜μ— 전달될 λ•Œ λ°°μ—΄μ˜ 값은 λ³΅μ‚¬λ˜μ–΄ μ „λ‹¬λœλ‹€.
    • μ•„λž˜ μ˜ˆμ‹œ μ°Έμ‘°.
let numberArray = [1, 2, 3, 4, 5]
var otherNumberArray = numberArray

print(numberArray) // [1, 2, 3, 4, 5]
print(otherNumberArray) // [1, 2, 3, 4, 5]

otherNumberArray[2] = 10

print(numberArray) // [1, 2, 3, 4, 5]
print(otherNumberArray) // [1, 2, 10, 4, 5]
  • λ°°μ—΄μ˜ μš”μ†Œκ°€ 클래슀의 μΈμŠ€ν„΄μŠ€μΈ 경우
    • 배열에 μ €μž₯된 값듀이 각각 λ°°μ—΄ μ™ΈλΆ€ 객체에 λŒ€ν•œ μ°Έμ‘°κ°€ λœλ‹€.
    • 같은 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” 배열듀은, κ·Έ 객체가 λ³€κ²½λ˜μ—ˆμ„ λ•Œ ν•¨κ»˜ λ³€κ²½λœλ‹€.
    • μ•„λž˜ μ˜ˆμ‹œ μ°Έμ‘°.
// An integer type with reference semantics
class IntegerReference {
    var value = 10
}
var firstIntegers = [IntegerReference(), IntegerReference()]
var secondIntegers = firstIntegers

// Modifications to an instance are visible from either array
firstIntegers[0].value = 100
print(secondIntegers[0].value)
// Prints "100"

// Replacements, additions, and removals are still visible
// only in the modified array
firstIntegers[0] = IntegerReference()
print(firstIntegers[0].value)
// Prints "10"
print(secondIntegers[0].value)
// Prints "100"

λ°°μ—΄μ˜ Copy-On-Write (COW)

Swift Standard Library의 λͺ¨λ“  κ°€λ³€ 크기 μ»¬λ ‰μ…˜κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ, 배열도 copy-on-write μ΅œμ ν™”λ₯Ό μ‚¬μš©ν•œλ‹€.

ν•œ 배열에 λŒ€ν•œ μ—¬λŸ¬ 볡사본이 μžˆλ”λΌ 해도, κ·Έ 쀑 ν•˜λ‚˜λ₯Ό μˆ˜μ •ν•˜κΈ° μ „κΉŒμ§€λŠ” 같은 μ €μž₯ 곡간을 κ³΅μœ ν•œλ‹€.

λ§Œμ•½ 볡사본에 λŒ€ν•œ μˆ˜μ •μ΄ 생기면, κ·Έ μ‹œμ μ— λΉ„λ‘œμ†Œ 볡사본이 λ³„λ„μ˜ μ €μž₯곡간을 λ§Œλ“€μ–΄ κ°–κ²Œ 되고, κ·Έ μžλ¦¬μ—μ„œ μˆ˜μ •μ΄ 이루어진닀.

즉, 배열이 λ‹€λ₯Έ (λ°°μ—΄μ˜)볡사본듀과 μ €μž₯ 곡간을 κ³΅μœ ν•˜λŠ” 경우, κ·Έ 배열에 λŒ€ν•΄ 처음으둜 μ΄λ£¨μ–΄μ§€λŠ” λ³€κ²½ 연산은 β€˜λ°°μ—΄μ˜ λ³΅μ‚¬β€™λΌλŠ” λΉ„μš©μ„ λ°œμƒμ‹œν‚΅λ‹ˆλ‹€. μ €μž₯ κ³΅κ°„μ˜ μœ μΌν•œ μ†Œμœ κΆŒμ„ κ°–λŠ” λ°°μ—΄λ§Œμ΄ μ œμžλ¦¬μ—μ„œ λ³€κ²½ 연산을 μˆ˜ν–‰ν•  수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

var numbers = [1, 2, 3, 4, 5]
var firstCopy = numbers
var secondCopy = numbers

// The storage for 'numbers' is copied here
numbers[0] = 100
numbers[1] = 200
numbers[2] = 300
// 'numbers' is [100, 200, 300, 4, 5]
// 'firstCopy' and 'secondCopy' are [1, 2, 3, 4, 5]

μœ„ μ˜ˆμ‹œμ—μ„œ, numbers 배열은 같은 μ €μž₯곡간을 κ³΅μœ ν•˜λŠ” 두 볡사본과 ν•¨κ»˜ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ›λž˜μ˜ 배열인 numbers 배열이 μˆ˜μ •λ  λ•Œ, κ·Έ μ‹œμ μ— numbers λŠ” λΉ„λ‘œμ†Œ μžμ‹ λ§Œμ˜ μœ μΌν•œ 볡사본을 λ§Œλ“€κ³ , κ·Έ λ‹€μŒ μˆ˜μ • μž‘μ—…μ„ ν•©λ‹ˆλ‹€. κ·Έ 이후 numbers 에 λŒ€ν•œ μˆ˜μ • μž‘μ—…μ€ μ œμžλ¦¬μ—μ„œ μˆ˜ν–‰λ©λ‹ˆλ‹€. 값이 μˆ˜μ •λœ 적이 μ—†λŠ” 두 볡사본은 μ—¬μ „νžˆ μ›λž˜μ˜ μ €μž₯ 곡간을 κ³΅μœ ν•©λ‹ˆλ‹€.