Many iOS and macOS applications use Dictionary for internal logic. A new Swift package called swift-collections introduces OrderedDictionary, a dictionary which keeps track of insertion order. This post presents an overview of OrderedDictionary and usage examples:

  1. OrderedDictionary Examples
    a. Insert Value For Key
    b. Get Value For Key
    c. Remove Key and Value
  2. Dictionary vs OrderedDictionary
    a. OrderedDictionary Maintains Insertion Order
  3. When To Use OrderedDictionary
    a. Ordered Counters
    b. Random Access To Unique, Ordered Elements

Note: To use OrderedDictionary, first add the swift-collections Swift package to your project. Then, import the OrderedCollections module:

import OrderedCollections

OrderedDictionary Examples

Insert Value For Key

var orderedDict: OrderedDictionary = [
    "key0": 0,
    "key1": 1
]

orderedDict["key2"] = 2

// orderedDict now contains, in order,
// "key0": 0, "key1": 1, "key2": 2

Get Value For Key

Like a traditional Dictionary, OrderedDictionary is a key-value store and can retrieve values using a specified key:

var orderedDict: OrderedDictionary = [
    "key0": 0,
    "key1": 1
]

// Returns the value 1
orderedDict["key1"]

Additionally, OrderedDictionary has an internal order and can retrieve values at a specific position in the order using the elements property:

// Returns the element at index 0
var element = orderedDict.elements[0]
element.key // "key0"
element.value // 0

Remove Key and Value

There are multiple ways to remove keys and values from an OrderedDictionary. One way is to remove a key and value explicitly, either specifying the key directly or the index the key and value are at:

// Remove a specific key
orderedDict.removeValue(forKey: "key1")

// Remove a key and value at a specific index
orderedDict.remove(at: 2)

Another method is to remove keys and values relative to the front and back of the OrderedDictionary:

// Remove keys and values from the front
orderedSet.removeFirst()
orderedSet.removeFirst(2)

// Remove keys and values from the back
orderedSet.removeLast()
orderedSet.removeLast(2)

OrderedDictionary also includes methods for removing all keys and values, and removing all keys and values that meet some filter criteria:

// Remove all keys and values
orderedDict.removeAll()

// Filter keys and values
orderedDict.removeAll { (key, value) -> Bool in
    // Filter criteria
}

Dictionary vs OrderedDictionary

Dictionary is an unordered collection of keys and associated values, often used as a key-value store. Like Dictionary, OrderedDictionary contains keys and associated values and can be used as a key-value store. Unlike Dictionary:

OrderedDictionary Maintains Insertion Order

As the name indicates, OrderedDictionary maintains key and value insertion order. This means an OrderedDictionary can efficiently retrieve a value for a specific key, like a traditional Dictionary, and also retrieve a key and value at a specific position, similar to a traditional Array.

To maintain key and value order, OrderedDictionary introduces an elements property. The elements property is an Array value, and can be used to iterate over or retrieve keys and values at a specific position in the order.

An important note, reassigning keys to different values does not change the order:

var orderedDict: OrderedDictionary = [
    "key0": 0,
    "key1": 1,
    "key2": 2
]

// orderedDict contains, in order,
// "key0": 0, "key1": 1, "key2": 2

orderedDict["key1"] = 100

// orderedDict contains, in order,
// "key0": 0, "key1": 100, "key2": 2

When To Use OrderedDictionary

Ordered Counters

A counter is often used to determine the number of occurrences unique elements have in a sequence. An ordered counter allows the occurrences of unique elements to be counted, while also preserving the first-seen order:

var sequence = [
    "a", "b", "a", "c", "b", "b", "b", "a"
]

var orderedCounter: OrderedDictionary<String,Int> = [:]

for item in sequence {
    orderedCounter[item, default: 0] += 1
}

// orderedCounter now contains, in order,
// "a": 3, "b": 4, "c": 1

// Accessing the key "b" returns 4, the number of 
// times "b" occurs in the sequence
orderedCounter["b"]

// Accessing the position 0 returns the element
// "a": 3, indicating "a" occurred first in the sequence
// and occurred a total of 3 times
var element = orderedCounter.elements[1]
element.key // "a"
element.value // 3

Random Access To Unique, Ordered Elements

When working with unique sequences, like time-series, it is often useful to access the elements of the unique sequence in order and using a unique identifier. OrderedDictionary provides a type that can do both:

var timeSeries = [
    ["id": "t0", "value": "0.1"],
    ["id": "t1", "value": "1.1"],
    ["id": "t2", "value": "2.1"]
]

var series: OrderedDictionary<String, Dictionary<String,String>> = [:]

for datapoint in timeSeries {
    series[datapoint["id"]!] = datapoint
}

// Accessing the key "t1" returns the datapoint
// associated with the id "t1"
series["t1"] // ["id": "t1", "value": "1.1"]

// Accessing the element at index 2 returns 
// the element associated with index 2 in the
// time series
var element = series.elements[2]
element.key // "t2"
element.value // ["id": "t2", "value": "2.1"]

Swift OrderedDictionary

That’s it! By using the swift-collections package and OrderedDictionary, you can take advantage of both Dictionary key-value store properties and element ordering in Swift.