Essential Swift Programming Snippets and Algorithms

Essential Swift Programming Snippets and Algorithms

Loops

Loop Forward

// Loop forward
for i in 0..

Loop in Reverse

// Loop in reverse
for index in stride(from: 5, through: 1, by: -1) {
    print(index) // 5, 4, 3, 2, 1
}

// OR
for i in (0..<10).reversed() {
    print(i)
}

Strings

String Manipulation

  • Convert String to Array of Strings containing 1 Character:
var strArr = str.characters.map { String($0) }
Join Array of Strings into 1 String:
var str = strArr.joined(separator: "")
Split String into array (requires import Foundation):
import Foundation
let fullNameArr = fullName.components(separatedBy: " ")
Split String into Characters (returns array of Subsequence):
let subsequences = str.characters.split(separator: " ") 
String(subsequences[0]) // to use as string
Convert String to Array of Characters:
sChars = Array(string.characters)

String/Character to Int

Convert Character to Int value (ASCII or Unicode value):

for char in string.unicodeScalars {
    print(char.value)
}

Get Int value (Unicode point) of a Character from a String:

extension Character {
  var unicodeValue: UInt32 {
    return String(self).unicodeScalars.first!.value
  }
  // OR
  var charValue: UInt16 {
    return (String(self) as NSString).character(at: 0)
  }
}

String Index

Need to have String.Index to access individual characters in a String:

  • str.startIndex // Index corresponding to 0
  • str.endIndex // Index corresponding to N-1
Advance Index
let s = "abcdef"
let idx = s.index(s.startIndex, offsetBy: 5)
s[idx] // → "f" (the Character, not the String)
Index From the Back
let s = "abcdef"
let rIdx = s.index(s.endIndex, offsetBy: -1)
// s[rIdx] → "f" (the Character, not the String) // Note: endIndex is not valid subscript
let rIdx2 = s.index(rIdx, offsetBy: -1)
s[rIdx2] // → "e" (the Character, not the String)
Safe Index
let safeIdx = s.index(s.startIndex, offsetBy: 400, limitedBy: s.endIndex)
safeIdx // → nil
String Slicing using Index
s[s.startIndex..

Array

Slice Array

Array(numbers[0..

Elements Dropping

Note: drop... methods return a new array slice.

var a = [1,2,3] 
var b = Array(a.dropFirst()) // Works even if a is empty
a.dropFirst(5) // Works even if greater than length of a
a.dropLast()
a.dropLast(4)

Character

Check if Character is Alphanumeric (Lowercase Example)

extension Character {
    var isAlphanumeric: Bool {
            return (self >= "a" && self <= "z") || (self >= "0" && self <= "9") // Add "A" and "Z" if needed
    }
}

Numbers

Absolute Value

abs(num) // If Int, returns Int too, if Double, returns Double

Infinity and NaN (Float, CGFloat, Double only)

Double.infinity, Double.nan, -Double.infinity (negative infinity)
someDouble.isFinite
someDouble.isInfinite
someDouble < Double.infinity
someDouble = Double.greatestFiniteMagnitude
someDouble.isInfinite // false

Misc Functions

Swap Values

  • Tuple swapping (Recommended):
var b = [1,2,3,4,5]
(b[0], b[1]) = (b[1], b[0])
swap(&b[0], &b[1]) // Caution: Returns an error if indices are the same.

Generate Random Number

var k: Int = random() % 10  // 0 - 9

Functions

Inout Parameters

func swap(wordArr: inout Array<String>, i: Int, j: Int) {
  // Modify wordArr; the original array passed will also be modified on return of this function (copy-in copy-out)
}

Reserve Capacity in Collections

Reserve capacity to avoid overhead of resizing:

var longestSubstring = [Character: Int](minimumCapacity: 256)
var dict = [Int:Int]()
dict.reserveCapacity(256)

Big O Notation

Complexity Hierarchy (Lowest to Highest)

  1. O(1)
  2. O(log N)
  3. O(N)
  4. O(N log N)
  5. O(N^2)
  6. O(2^N)
  7. O(N!)

Big O Other Notes

  1. Doubling Sequence (e.g., 1+2+4+8+…+N):

    Approaches 2N (exactly 2N-1). This is equivalent to $\sum_{i=0}^{N} 2^i = 2^{N+1} – 1$, which is still $O(2^N)$ if $N$ is the number of terms, but if $N$ is the final value, it’s $O(N)$.

  2. Halving Sequence (e.g., N + N/2 + N/4 + … + 1):

    Approaches 2N. If $N$ is excluded: $(N/2) + (N/4) + … + 1$ approaches N, thus $O(N)$.

  3. Arithmetic Sequence (e.g., 1+2+3+…+N):

    Equals $(N(N+1)) / 2$, resulting in $O(N^2)$.

  4. Recursion (e.g., Fibonacci):

    Complexity is often $\text{branches}^{\text{depth}}$. For Fibonacci (two branches), this is $O(2^N)$, where $N$ is the depth.

  5. Nested Loops (Second loop decreases by one):

    Example: $N + (N-1) + … + 1 = (N(N+1)) / 2$, resulting in $O(N^2)$.

  6. Loop advancing/decreasing by powers of two:

    Results in $O(\log N)$.

Bits Operations

  1. Determine if Power of 2:
    N & (N-1) == 0
  2. Determine Lowest Power of 2 Near N:

    Repeat N = N & (N-1) until $N$ is 0. The number of times this operation is performed is the power of 2.

  3. Find Unique Value from 3 Pairs (Two equal, one unique):
    X1 \text{ XOR } X2 \text{ XOR } X3 = \text{answer}
  4. Swap Two Numbers Without Additional Space (XOR Swap):
    x = x \text{ XOR } y
    y = x \text{ XOR } y
    x = x \text{ XOR } y
  5. Multiplication by Powers of Two:

    To multiply by two, shift left 1 time. To multiply by $2^k$, shift left $k$ times.

Heap Formulas (Array Representation)

  • A heap with $n$ nodes has height $h = \lfloor\log_2(n)\rfloor$.
  • If the lowest level is completely full, it contains $2^h$ nodes. The rest of the tree above it contains $2^h – 1$ nodes.
  • Leaf Nodes Location: Leaf nodes are always located at array indices $\lfloor n/2 \rfloor$ to $n-1$, where $n$ is the number of nodes.
  • Heapify from Array: Start processing from index $(\lfloor n/2 \rfloor) – 1$, up to 0, since indices $\lfloor n/2 \rfloor$ to $n-1$ are already leaf nodes.
  • Number of Leaf Nodes in a complete binary tree (heap) is $\lceil n/2 \rceil$.

Misc Notes

Midpoint Calculation to Avoid Integer Overflow

When computing mid for binary search or merge sort:

let mid = left + ((right - left) / 2)

Reallocation Factor in Swift

  • Array: 2
  • String: 2
  • Dictionary: 1.333