Swift Ordered Dictionary

Dec 13, 2021 2 min read
Swift Ordered Dictionary

Dictionaries are powerful, but I hate the fact that they are unordered. But Swift has "fixed" this by providing something new, Collections.

Official Documentations:

  • Standard (unordered) dictionaries can be found here.
  • Collections (ordered) dictionaries can be found here.

First import it:

import OrderedCollections

Declaration

An empty collection can be initialized like this:

var dataDiccionary: OrderedDictionary<String, [String]> = [:]

In the example above we are declaring a key of type String which contains an array of values of type String.

You could also create an ordered dictionary with any key type that conforms to the Hashable protocol.

let responses: OrderedDictionary = [
  200: "OK",
  403: "Access forbidden",
  404: "File not found",
  500: "Internal server error",
]

Call Keys and Values

The keys collection is of type OrderedSet<Key>, containing all the keys in the original dictionary.

let d: OrderedDictionary = [2: "two", 1: "one", 0: "zero"]
d.keys // [2, 1, 0] as OrderedSet<Int>

The values collection is a mutable random-access collection of the values in the dictionary:

d.values // "two", "one", "zero"
d.values[2] = "nada"
// `d` is now [2: "two", 1: "one", 0: "nada"]
d.values.sort()
// `d` is now [2: "nada", 1: "one", 0: "two"]

Both views store their contents in regular Array values, accessible through their elements property.

How to Loop through an Ordered Dictionary

Let's suppouse we have the following dictionary:

@Published var transactionsWalletDiccionary: [String: [TransactionsClassAModel]] = [:]

To loop inside a SwiftUI View:

ForEach(transactionsWalletDiccionary, id: \.self) { transactionsInChain in
    // Let's say you want to get the keys of that transaction only:
    ForEach(coinTransactions.keys, id: \.self) { transactionDate in
        ...
    }

    // If you wanted to iterate through each of the values in the keys, you can do the following: (transactionDate is the String key)
    ForEach(coinTransactions[transactionDate]!, id: \.self) { transactionData in
        ...
    }
}

Exceptions:

Some times when you use navigationlinks and you loop in the dictionary and the data is refreshed, your view will go 1 view back in the navigationlink. To solve this and account for predictability you can loop the following way:

// Suppouse you have some data:
let data = updateAPIDataViewModel.data[someKey]
// Get the total count
let dataCount: Int = data.count

// Loop through it
ForEach (0..<dataCount) { counter in
    // You can pass the data to a function like:
    myFunc(data: data[counter])
}

Performance

Like the standard Dictionary type, the performance of hashing operations in OrderedDictionary is highly sensitive to the quality of hashing implemented by the Key type. Failing to correctly implement hashing can easily lead to unacceptable performance, with the severity of the effect increasing with the size of the hash table.

In particular, if a certain set of keys all produce the same hash value, then hash table lookups regress to searching an element in an unsorted array, i.e., a linear operation. To ensure hashed collection types exhibit their target performance, it is important to ensure that such collisions cannot be induced merely by adding a particular list of keys to the dictionary.

The easiest way to achieve this is to make sure Key implements hashing following Hashable's documented best practices. The conformance must implement the hash(into:) requirement, and every bit of information that is compared in == needs to be combined into the supplied Hasher value. When used correctly, Hasher produces high-quality, randomly seeded hash values that prevent repeatable hash collisions.

When Key correctly conforms to Hashable, key-based lookups in an ordered dictionary is expected to take O(1) equality checks on average. Hash collisions can still occur organically, so the worst-case lookup performance is technically still O(n) (where n is the size of the dictionary); however, long lookup chains are unlikely to occur in practice.

Implementation Details

An ordered dictionary consists of an ordered set of keys, alongside a regular Array value that contains their associated values.

Great! Next, complete checkout for full access to ArturoFM.
Welcome back! You've successfully signed in.
You've successfully subscribed to ArturoFM.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.