Intro to Swift Collections
Tags: swift, tutorial
Published: 2020-01-13 16:42:17

# My notes of Swift 5 language study
## Built-In Collections

Collections of different kinds are supported by the standard library. Evermore does Swift put emphasis on sequences and collections resulting in very extensible model.

### Arrays and Mutability

Most common collections in Swift - an ordered container of elements of the same type, providing random element access. 
```
let FibonacciNumbers = [0, 1, 1, 2, 3, 5]
```

Modification of this array using `append(_:)` will result in compile error. How come?!

Because `let` defines constants, while `var` variables. 

Stick to constant by default, it's safer.

```
var mutableFibs = [0, 1, 1, 2, 3, 5]
mutableFibs.append(8)
mutableFibs.append(contentsOf: [13, 21])
// [0, 1, 1, 2, 3, 5, 8, 13, 21]
```

Evidently, `let` variable containing reference to a class instance guarantees that the reference will never change, but he object the reference points to can chang, indeed. 

#### Value semantics
An existing array assigned to a different variable copies it over. 

```
var x = [1, 2, 3]
var y = x
y.append(4)
```
x is never modified, while a copy of it is made. Same thing happens with passing an array to a function - a local copy is made.

If to peep in `NSArray` of Foundation, there are no mutating methods. `NSMutableArray` is needed. But non-mutating `NSArray` reference can be mutated "underneath"
```
let a = NSMutableArray(array: [1,2,3])
// I want a to be immutable

let b: NSArray = a

a.insert(4, at:3)

//fail :)
```

The correct way to write this therefore is to create a copy upon assignment
```text
let c = NSMutableArray(array: [1,2,3])
//I want d to be immutable

let d = c.copy() as! NSArray

c.insert(4, at: 3)

```

### Array Indexing

Swift arrays provide all the usual operations like `isEmpty`, subscripting `[]`, and `count`.
Fatal errors occur whenever out-of-bounds elements are requested.

Iteration over an array
```text
for x in array
```

Iterate over all but the first element
```text
for x in array.dropFirst()
```

Iterate over all but the last five elements
```text
for x in array.dropLast(5)
```

Number all the elements
```text
for (num, element) in array.enumerated()
```

Find location of a specific element 
```text
if let index = array.firstIndex {
    return matchingLogic($0)
}
```

Transform all the elements 
```text
array.map {
    return transformLogic($0)
}
```

Fetch only the creterion matching elements
```text
array.filter {
    match($0)
}
```

Note: subscripting operation that responds to an invalid index with a fatal error is arguably an "unsafe" operation. Swift discourages use of indecis. Mind, though, that subscripting in regard to memory safety always performs bound checks to prevent **null pointer exception**

Other operations like `first` and `last` return an optional value, which is `nil` if the array is empty. 
`removeLast` method will halt if called on empty array, `popLast` is safe.If array is used as a a stack checking for emptiness is encouraged so as not to fiddle with optional.


### `map`
```text
var squared: [Int] = []
for fib in FibonacciNumbers {
    squared.append(fib * fib)
}
squared // [0, 1, 1, 4, 9, 25]

let squares = FibonacciNumbers.map {fib in fib * fib}
squares // [0, 1, 1, 4, 9, 25]

```

As a side note, `map` method isn't hard to write, it's a generic for loop
`Element` is the generic placeholder fpr whatever type the array contains, amd T is a new placeholder that represent the result of the elelement transformation. `MyMap` function is oblivious to the types. 

Ideally thought, signature must be `func MyMap<T>(_ transform:(Element) throws -> T) rethrows -> [T]`, meaning that `MyMap` will forward any error the transformation function might through to the caller.