Skip to content

Collections

Swift’s collection types—Array, Dictionary, Set, and tuples—provide powerful, type-safe ways to store and manipulate data. They are optimized with copy-on-write and conform to protocols like Collection and Sequence.

Arrays

Ordered, index-based collections that allow duplicates.

Example: Basic Array:

swift
var numbers = [1, 2, 3]
numbers.append(4)
numbers[0] = 0
print(numbers) // [0, 2, 3, 4]

Example: Array Operations:

swift
numbers.insert(5, at: 1)
numbers.remove(at: 2)
print(numbers) // [0, 5, 3, 4]

let slice = numbers[1...2] // [5, 3]
let contains = numbers.contains(5) // true

Dictionaries

Unordered key-value pairs with unique keys.

Example: Basic Dictionary:

swift
var scores: [String: Int] = ["Alice": 90, "Bob": 85]
scores["Charlie"] = 95
scores["Bob"] = nil // Remove key
print(scores) // ["Alice": 90, "Charlie": 95]

Example: Dictionary Operations:

swift
let keys = Array(scores.keys) // ["Alice", "Charlie"]
let values = Array(scores.values) // [90, 95]
let merged = scores.merging(["David": 80]) { current, _ in current }
print(merged) // ["Alice": 90, "Charlie": 95, "David": 80]

Sets

Unordered collections of unique elements.

Example: Basic Set:

swift
var colors: Set<String> = ["Red", "Blue"]
colors.insert("Green")
colors.remove("Red")
print(colors) // ["Blue", "Green"]

Example: Set Operations:

swift
let otherColors: Set = ["Blue", "Yellow"]
let union = colors.union(otherColors) // ["Blue", "Green", "Yellow"]
let intersection = colors.intersection(otherColors) // ["Blue"]
let difference = colors.subtracting(otherColors) // ["Green"]

Tuples

Group multiple values, optionally named, immutable by default.

Example: Basic Tuple:

swift
let point = (x: 1.0, y: 2.0)
print(point.x) // 1.0

let status = (200, "OK")
print(status.0) // 200

Example: Tuple Decomposition:

swift
let (code, message) = status
print("Code: \(code), Message: \(message)")

Collection Protocols

Swift’s collections conform to protocols like Sequence, Collection, and MutableCollection.

Example: Custom Collection:

swift
struct CircularBuffer<T>: Collection {
    private var elements: [T]
    private let capacity: Int
    private var startIndex: Int = 0
    
    init(capacity: Int) {
        self.capacity = capacity
        self.elements = []
    }
    
    var startIndex: Int { return 0 }
    var endIndex: Int { return elements.count }
    func index(after i: Int) -> Int { return i + 1 }
    subscript(position: Int) -> T { return elements[position] }
}

var buffer = CircularBuffer<Int>(capacity: 3)
buffer.elements = [1, 2, 3]
for item in buffer {
    print(item) // 1, 2, 3
}

Functional Operations

Collections support functional methods like map, filter, reduce.

Example:

swift
let squares = numbers.map { $0 * $0 } // [0, 25, 9, 16]
let evens = numbers.filter { $0 % 2 == 0 } // [0, 4]
let sum = numbers.reduce(0, +) // 12
let sorted = numbers.sorted { $0 < $1 } // [0, 3, 4, 5]

Lazy Collections

Defer operations until results are needed.

Example:

swift
let lazySquares = numbers.lazy.map { $0 * $0 }
print(Array(lazySquares.prefix(2))) // [0, 25]

Copy-on-Write

Collections use copy-on-write to optimize memory.

Example:

swift
var array1 = [1, 2, 3]
var array2 = array1 // Shares storage
array2.append(4) // Copies storage
print(array1) // [1, 2, 3]
print(array2) // [1, 2, 3, 4]

Best Practices

  • Choose Correct Type: Use Set for uniqueness, Dictionary for key-value, Array for order.
  • Immutable Collections: Prefer let for thread safety.
  • Functional Methods: Use map, filter for declarative code.
  • Lazy Operations: Optimize for large datasets.
  • Type Safety: Specify element types explicitly in APIs.
  • Custom Collections: Conform to Collection for advanced needs.

Troubleshooting

  • Index Out of Range: Validate indices before access.
  • Unexpected Copies: Ensure copy-on-write isn’t overused.
  • Set Duplicates: Verify Hashable conformance for custom types.
  • Performance: Profile with Instruments for large collections.
  • Thread Safety: Use actors or locks for concurrent access.

Example: Comprehensive Collection Usage

swift
struct Inventory {
    var items: [String]
    var prices: [String: Double]
    var categories: Set<String>
    
    func analyze() -> (count: Int, totalValue: Double, uniqueCategories: Int) {
        let count = items.count
        let totalValue = prices.values.reduce(0, +)
        let uniqueCategories = categories.count
        return (count, totalValue, uniqueCategories)
    }
    
    func filterByCategory(_ category: String) -> [String] {
        return items.filter { categories.contains(category) }
    }
}

var inventory = Inventory(
    items: ["Laptop", "Phone", "Tablet"],
    prices: ["Laptop": 999.99, "Phone": 799.99, "Tablet": 499.99],
    categories: ["Electronics", "Portable"]
)

let analysis = inventory.analyze()
print("Items: \(analysis.count), Value: \(analysis.totalValue), Categories: \(analysis.uniqueCategories)")

let electronics = inventory.filterByCategory("Electronics")
print(electronics) // ["Laptop", "Phone", "Tablet"]

Released under the MIT License.